Jump To …

model.js

Recline Backbone Models

this.recline = this.recline || {};
this.recline.Model = this.recline.Model || {};

(function($, my) {

A Dataset model

A model has the following (non-Backbone) attributes:

  • fields: (aka columns) is a FieldList listing all the fields on this Dataset (this can be set explicitly, or, will be set by Dataset.fetch() or Dataset.query()
  • currentDocuments: a DocumentList containing the Documents we have currently loaded for viewing (you update currentDocuments by calling query)
  • docCount: total number of documents in this dataset
my.Dataset = Backbone.Model.extend({
  __type__: 'Dataset',
  initialize: function(model, backend) {
    _.bindAll(this, 'query');
    this.backend = backend;
    if (backend && backend.constructor == String) {
      this.backend = my.backends[backend];
    }
    this.fields = new my.FieldList();
    this.currentDocuments = new my.DocumentList();
    this.facets = new my.FacetList();
    this.docCount = null;
    this.queryState = new my.Query();
    this.queryState.bind('change', this.query);
    this.queryState.bind('facet:add', this.query);
  },

query

AJAX method with promise API to get documents from the backend.

It will query based on current query state (given by this.queryState) updated by queryObj (if provided).

Resulting DocumentList are used to reset this.currentDocuments and are also returned.

  query: function(queryObj) {
    var self = this;
    this.trigger('query:start');
    var actualQuery = self._prepareQuery(queryObj);
    var dfd = $.Deferred();
    this.backend.query(this, actualQuery).done(function(queryResult) {
      self.docCount = queryResult.total;
      var docs = _.map(queryResult.hits, function(hit) {
        var _doc = new my.Document(hit._source);
        _doc.backend = self.backend;
        _doc.dataset = self;
        return _doc;
      });
      self.currentDocuments.reset(docs);
      if (queryResult.facets) {
        var facets = _.map(queryResult.facets, function(facetResult, facetId) {
          facetResult.id = facetId;
          return new my.Facet(facetResult);
        });
        self.facets.reset(facets);
      }
      self.trigger('query:done');
      dfd.resolve(self.currentDocuments);
    })
    .fail(function(arguments) {
      self.trigger('query:fail', arguments);
      dfd.reject(arguments);
    });
    return dfd.promise();
  },

  _prepareQuery: function(newQueryObj) {
    if (newQueryObj) {
      this.queryState.set(newQueryObj);
    }
    var out = this.queryState.toJSON();
    return out;
  },

  toTemplateJSON: function() {
    var data = this.toJSON();
    data.docCount = this.docCount;
    data.fields = this.fields.toJSON();
    return data;
  }
});

A Document (aka Row)

A single entry or row in the dataset

my.Document = Backbone.Model.extend({
  __type__: 'Document'
});

A Backbone collection of Documents

my.DocumentList = Backbone.Collection.extend({
  __type__: 'DocumentList',
  model: my.Document
});

A Field (aka Column) on a Dataset

Following attributes as standard:

  • id: a unique identifer for this field- usually this should match the key in the documents hash
  • label: the visible label used for this field
  • type: the type of the data
my.Field = Backbone.Model.extend({
  defaults: {
    id: null,
    label: null,
    type: 'String'
  },

In addition to normal backbone initialization via a Hash you can also just pass a single argument representing id to the ctor

  initialize: function(data) {

if a hash not passed in the first argument is set as value for key 0

    if ('0' in data) {
      throw new Error('Looks like you did not pass a proper hash with id to Field constructor');
    }
    if (this.attributes.label == null) {
      this.set({label: this.id});
    }
  }
});

my.FieldList = Backbone.Collection.extend({
  model: my.Field
});

A Query object storing Dataset Query state

my.Query = Backbone.Model.extend({
  defaults: function() {
    return {
      size: 100
      , from: 0
      , facets: {}

http://www.elasticsearch.org/guide/reference/query-dsl/and-filter.html , filter: {} list of simple filters which will be add to 'add' filter of filter

      , filters: []
    }
  },

Set (update or add) a terms filter http://www.elasticsearch.org/guide/reference/query-dsl/terms-filter.html

  addTermFilter: function(fieldId, value) {
    var filters = this.get('filters');
    var filter = { term: {} };
    filter.term[fieldId] = value;
    filters.push(filter);
    this.set({filters: filters});

change does not seem to be triggered ...

    this.trigger('change');
  },
  addFacet: function(fieldId) {
    var facets = this.get('facets');

Assume id and fieldId should be the same (TODO: this need not be true if we want to add two different type of facets on same field)

    if (_.contains(_.keys(facets), fieldId)) {
      return;
    }
    facets[fieldId] = {
      terms: { field: fieldId }
    };
    this.set({facets: facets}, {silent: true});
    this.trigger('facet:add', this);
  }
});

A Facet (Result)

my.Facet = Backbone.Model.extend({
  defaults: function() {
    return {
      _type: 'terms',

total number of tokens in the facet

      total: 0,

number of facet values not included in the returned facets

      other: 0,

number of documents which have no value for the field

      missing: 0,

term object ({term: , count: ...})

      terms: []
    }
  }
});

A Collection/List of Facets

my.FacetList = Backbone.Collection.extend({
  model: my.Facet
});

Backend registry

Backends will register themselves by id into this registry

my.backends = {};

}(jQuery, this.recline.Model));