I ended up working the way I wanted. Many-to-many relationships are maintained in the database, but relationships can only be accessed in my Backbone models in one direction. I decided that the Person models would be self-contained, and the PersonGroup models would have a set of references to the Person models to which they are attached.
The key points at which everything was done was to specify includeInJSON: "ID" and remove reverseRelation . This still allows you to access model references in JavaScript, but it is correctly serialized and deserialized in JSON. Person models simply do not have access to the navigation properties of the groups in which they are located, however they can exist in several groups just fine.
I just assumed that using a list of identifiers would make it possible to jump over hoops to resolve links, but Backbone-relational seems to use the Backbone global model repository to resolve links by ID without creating duplicate models. (for example, three different groups can refer to the same Person, and only one model is ever created).
var Person = Backbone.RelationalModel.extend( { idAttribute: "ID", }); var PersonGroup = Backbone.RelationalModel.extend( { idAttribute: "ID", relations: [ { type: Backbone.HasMany, key: "People", relatedModel: "Person", collectionType: "PersonCollection", includeInJSON: "ID", }, ], });
And here is the rest of the plumbing, if it helps anyone. You can define Backbone.Collections as follows and get them through separate API requests:
var PersonCollection = Backbone.Collection.extend( { model: Person, url: "/api/person", }); var PersonGroupCollection = Backbone.Collection.extend( { model: PersonGroup, url: "/api/persongroup", }); var PersonModels = new PersonCollection(); var GroupsModels = new PersonGroupCollection(); this.PersonModels.fetch(); this.GroupsModels.fetch(); this.People = kb.collectionObservable( this.PersonModels, { factories: { "models": PersonViewModel, }, } ); this.PersonGroups = kb.collectionObservable( this.GroupsModels, { factories: { "models": PersonGroupViewModel, "models.People.models": PersonViewModel, }, } );
I have included specific Knockback.js collections to use Knockout.js bindings. Only one ViewModel is created for each model, so change tracking is distributed throughout the application.