Backbone.js集合upsert?

Bri*_*chl 6 backbone.js

我正在使用Backbone.js构建一个应用程序.我的一些服务器端API将在特定时间后返回所有新的或更改的模型.其中一些对象对我的收藏可能是新的,所以我可以添加它们.其他可能已经存在,在这种情况下,我想更新现有的模型.所以基本上我正在寻找upsert(更新或插入)功能.

这类似于0.9.0中添加的{add:true}选项,除了我还想要更新.

有一个简单/已知的方法来做到这一点?更新代码似乎并不难,但我不想重新发明轮子.

fgu*_*len 5

我用通用方法解决了这种情况:

App.Utils = {
  refreshCollection: function( collection, collectionJSON ){
    // update/add
    _( collectionJSON ).each( function( modelJSON ) {
      var model = collection.get( modelJSON.id );
      if( model ) {
        model.set( modelJSON );
      } else {
        collection.add( modelJSON );
      }
    });

    // remove
    var model_ids_to_keep     = _( collectionJSON ).pluck( "id" );
    var model_ids             = collection.pluck( "id" );
    var model_ids_to_remove   = _( model_ids ).difference( model_ids_to_keep )

    _( model_ids_to_remove ).each( function( model_id_to_remove ){
      collection.remove( model_id_to_remove );
    });
  },
}
Run Code Online (Sandbox Code Playgroud)

PARAMS

  • collection:是一个Backbone.Collection
  • collectionJSON:是一个包含哈希样式的模型数据的数组.典型的JSON响应.

我确信它可以被优化,尤其是删除部分.但由于我仍在进行测试,因此我保持这样可读性.

使用示例

// code simplified and no tested
var VolatileCollection = Backbone.Collection.extend({
  // url:
  // model:
  // so on ... 
})

var PersistentCollection = Backbone.Collection.extend({
  // url: not needed due this Collection is never synchronized or changed by its own
  //   change the VolatileCollection instead, all changes will be mirrored to this Collection
  //   through events
  // model: the same

  initialize: function( opts ){
    this.volatileCollection = opts.volatileCollection;
    this.volatileCollection.on( "reset", this.update, this );
    this.volatileCollection.on( "change", this.update, this );
  }

  update: function(){
    App.Utils.refreshCollection( this, this.volatileCollection.toJSON() );
  }
})

var volatileCollection = new VolatileCollection();
var persistentCollection = new PersistentCollection({ volatileCollection: volatileCollection });

volatileCollection.fetch();
Run Code Online (Sandbox Code Playgroud)


Bri*_*chl 3

注意:这个答案是为 Backbone v0.9 编写的。自那时起,Backbone v1.0 已发布,其中包含此处collection.set()描述的方法。这可能是一个更好的解决方案。

我在周末整理了自己的版本。我会把它放在这里以防其他人发现这个线程,但我仍然很高兴看到可能存在的任何其他解决方案。

我通过修改 Backbone.js 源代码来做到这一点,这不一定是个好主意,但很简单。有两个变化,首先将此函数添加到 Backbone.Collection 原型中:

//**upsert** takes models and does an update-or-insert operation on them
//So models that already exist are updated, and new models are added
upsert: function (models, options) {
    var self = this;
    options || (options = {});
    models = _.isArray(models) ? models.slice() : [models];


   var addModels = [];
    _.each(models, function (newModel) {
        var n = self._prepareModel(newModel, options);
        var existingModel = self.get(n.id);
        if (existingModel) {
            existingModel.set(n, options);
        } else {
            addModels.push(n);
        }
    });

    if (!_.isEmpty(addModels)) {
    self.add(addModels, options);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后将 Backbone.Collection.fetch() 函数中的一行修改为:

collection[options.add ? 'add' : (options.upsert ? "upsert" : 'reset')](collection.parse(resp, xhr), options);
Run Code Online (Sandbox Code Playgroud)

这使您可以致电fetch({upsert:true})以获得我正在寻找的行为。