In addition to basic attribute data like email addresses, phone numbers, and birthdates, Waterline can dynamically store and retrieve linked sets of records using associations. When .populate()
is called on a query, each of the resulting records will contain one or more populated values. Each one of those populated values is a snapshot of the record(s) linked to that particular association at the time of the query.
The type of a populated value is either:
null
, or a plain old JavaScript object (POJO), (if it corresponds to a "model" association) orFor example, assuming we're dealing with orders of adorable wolf puppies:
Order.find()
.populate('buyers') // a "collection" association
.populate('seller') // a "model" association
.exec(function (err, orders){
// this array is a snapshot of the Customers who are associated with the first Order as "buyers"
orders[0].buyers;
// => [ {id: 1, name: 'Robb Stark'}, {id: 6, name: 'Arya Stark'} ]
// this object is a snapshot of the Company that is associated with the first Order as the "seller"
orders[0].seller;
// => { id: 42941, corporateName: 'WolvesRUs Inc.' }
// this array is empty because the second Order doesn't have any "buyers"
orders[1].buyers;
// => []
// this is `null` because there is no "seller" associated with the second Order
orders[1].seller;
// => null
});
Changes to populated values are persisted (i.e. saved to the database) by calling .save()
on the record they are attached to. You cannot call .save()
directly on a populated value.
Changing or remove the linked record of a "model" association can be accomplished by simply setting the property directly on the original record:
orders[1].seller = { corporateName: 'Wolf Orphanage' };
"collection" associations, on the other hand, do have a couple of special (non-enumerable) methods for associating and disassociating linked records. However, .save()
must still be called on the original record in order for changes to be persisted to the database.
orders[1].buyers.add({ name: 'Jon Snow' });
orders[1].save(function (err) { ... });
Finally, to put it all together:
Order.find()
.populate('buyers')
.exec(function (err, orders){
orders[1].buyers.add({ name: 'Jon Snow' });
orders[1].seller = { corporateName: 'Wolf Orphanage' };
orders[1].save(function (err) {
if (err) {
// handle error (e.g. `return res.serverError(err);` )
return;
}
// We successfully created a new Customer named Jon and added
// him to `order[1]` as one of its "buyers".
// We also created a new company and set it as `order[1]`'s "seller".
//
// If we had provided only a primary key value instead of an object,
// in both cases Waterline would have tried to associate existing
// Customer and Company records rather than creating new ones.
});
});