NOTE: This answer was written for Backbone v0.9. Since then Backbone v1.0 has released, which contains the collection.set()
method described here. That will likely be a better solution.
I threw together my own version of this over the weekend. I'll put it up here in case anybody else finds this thread, but I'd still be happy to see any other solutions that might be out there.
I did this by modifying the Backbone.js source, which is not necessarily a great idea, but it was easy. There were two changes, first add this function to the Backbone.Collection prototype:
//**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);
}
}
Then modify one line in the Backbone.Collection.fetch() function to read:
collection[options.add ? 'add' : (options.upsert ? "upsert" : 'reset')](collection.parse(resp, xhr), options);
This allows you to call fetch({upsert:true})
to get the behavior I was looking for.