Salivan
Salivan

Reputation: 1905

Mongoose relations design

I've recently started using Mongoose with Express.js in a Node.js application and I have a question about a proper way to design my schemas.

I have several schemas that have some relationships, i.e. Location schema has an array of Objects (it's not a JS object in this context), and Object schema has its Location property. I've learned that relationships in Mongoose are resolved using population, but when I implemented this approach I noticed that I have to type a lot of duplicate code, i.e. whenever I want to create a new Object I have to also update the Location's array of Objects and then assign the Location to the Object's property. Wouldn't it be more trivial to just manually assemble all the Objects that has a locationId property equal to the Location that I want to get from the database in a separate query?

I have also considered just storing Objects in an array in a Location document (as subdocuments) but I decided that I want to be able to work with Objects (create, remove, update) separately from Locations (without querying a Location) so this approach doesn't fit my needs I guess. But then population has its drawbacks too in my case, so I guess it's really the best to just go with manually collecting Objects of a specific Location in a separate query by that Location's id.

I would like to hear an opinion of some professional or advanced user of this technology on designing Mongoose schemas so that I and others don't get into trouble later maintaining and scaling our applications.

Here are my current schemas in question:

var locationSchema = new mongoose.Schema({
    title: String,
    objects: [{ type: String, ref: 'object' }]
});

var objectSchema = new mongoose.Schema({
    title: String,
    location: { type: String, ref: 'location' }
});

Upvotes: 1

Views: 618

Answers (1)

num8er
num8er

Reputation: 19372

Checkout this example

db/schemas.js:

const Schema = mongoose.Schema;

const ObjectSchema = {
    title: Schema.Types.String
}

const LocationSchema = new Schema({
    title: Schema.Types.String,
    objects: [{type: Schema.Types.ObjectId, ref: 'Object'}]
})

module.exports = {
  Object: ObjectSchema,
  Location: LocationSchema
};




db/model.js:

const 
 mongoose = require('mongoose'),
 schemas = require('./schemas');

module.exports = model => mongoose.model(model, schemas[model+'Schema']);




usage:

const 
  model = require('./db/model'),
  LocationModel = model('Location');

LocationModel
  .findOne({_id: 'some id here'})
  .populate('objects')
  .exec((err, LocationInstance) => {
    console.log(LocationInstance.title, ' objects:', LocationInstance.objects); 
  });




when You create an object and want to relate to location:

const 
  model = require('./db/model'),
  ObjectModel = model('Object'),
  LocationModel = model('Location');

let 
  ObjectInstance = new ObjectModel({title: 'Something'});
  ObjectInstance.save((err, result) => {
    LocationModel
      .findByIdAndUpdate(
        'some id here', 
        {$push: {objects: ObjectInstance._id}},
        (err) => {
          console.log('Object:', ObjectInstance.title, ' added to location');
        });
  });




updating object data:

  const 
    model = require('./db/model'),
    ObjectModel = model('Object');

  let id = 'id of object';

  ObjectModel
    .findByIdAndUpdate(
      id, 
      {title: 'Something #2'},
      (err) => {
        console.log('Object title updated');
      });




finding location by object:

  const 
    model = require('./db/model'),
    LocationModel = model('Object');

  let id = 'id of object';

  LocationModel
    .findOne({objects: id})
    .populate('objects')
    .exec((err, LocationInstance) => {
      console.log('Location objects:', LocationInstance.objects);
    });

nothing special findOne({objects: id}) will search inside location documents that has relation by id in objects array


any other question welcome (:

Upvotes: 1

Related Questions