Bill
Bill

Reputation: 1205

mongoose different ways to reference subdocuments?

This syntax is straight from the mongoose documentation on subtypes. However, I've also seen this alternate reference to subdocs. What is the difference?

https://mongoosejs.com/docs/subdocs.html

var childSchema = new Schema({ name: 'string' });

var parentSchema = new Schema({
  // Array of subdocuments
  children: [childSchema],
  // Single nested subdocuments. Caveat: single nested subdocs only work
  // in mongoose >= 4.2.0
  child: childSchema
});

An alternate type of reference to subdocs

var childSchema = new Schema({ name: 'string' });

mongoose.model('children', childSchema);

var parentSchema = new Schema({
  children: {
    type: Schema.Types.ObjectId,
    ref: 'children'
  },
});

Upvotes: 6

Views: 3927

Answers (3)

gazdagergo
gazdagergo

Reputation: 6691

I have completed Ravi Shankar Bharti Case 2 with some data writing example. Let's use a book-author scenario:

const authorSchema = new Schema({ name: 'string' });
const authorModel = mongoose.model('authors', authorSchema);
    
const bookSchema = new Schema({
  title: String,
  author: {
    type: Schema.Types.ObjectId,
    ref: 'author'
  },
});

const bookModel = mongoose.model('books', bookSchema)

const authorData = { name: "John Doe" }

// Check if author does exists. Insert if not or find if yes
const options = {
  upsert: true,
  new: true,
  setDefaultsOnInsert: true
};
const anAuthor = await authorModel.findOneAndUpdate(authorData, authorData, options)

// Insert a new book with reference to `anAuthor`
const aBook = new bookModel({ title: "MyBook" })
aBook.set({ author: anAuthor })
await aBook.save()

In this syntax, child documents will be stored separately, and they reference id (_id) will be stored in the parent document.

Sample documents in this case will look something like this:

// authors documents
{ _id : "authorId1" , name : "John Doe"}
{ _id : "authorId2" , name : "Iron Man"}
{ _id : "authorId3" , name : "Thor Odinson"}

//books document
{ 
  _id : "parent_random_generated_id"
  title: "MyBook",
  author : "authorId1",
  ...
}

And for reading, you can use populate:

let result = await bookModel.find()
result = await authorModel.populate(result, { path: 'author' })

Upvotes: 2

cEeNiKc
cEeNiKc

Reputation: 1318

Difference is pretty simple. The former one where you are just defining schema for child won't create a separate collection for the children in the database instead you will embed the whole child document in the parent.

And in the later one you are defining a model for the child schema by calling mongoose.model which creates a separate collection of children in the database and you can then reference child documents in the parent document without embedding the whole child document in the parent by just adding the child _id.

Upvotes: 1

Ravi Shankar Bharti
Ravi Shankar Bharti

Reputation: 9268

The above two syntax are totally different, In one the actual sub-document(children ) is stored in the parent document, but in the other one, a new document is stored in the children collection and only its reference is stored in the parent document.

Case 1:

var childSchema = new Schema({ name: 'string' });

var parentSchema = new Schema({
  // Array of subdocuments
  children: [childSchema],
  // Single nested subdocuments. Caveat: single nested subdocs only work
  // in mongoose >= 4.2.0
  child: childSchema
});

In this given syntax, parent document will have the child document stored in the parent document as well.

A sample document in the parent sollection will look like this:

{ 
  _id : "parent_random_generated_id"
  children :[{ _id : "childid1" , name : "Captain America"},
             { _id : "childid2" , name : "Iron Man"},...],
  child : {_id : "childid3" , name : "Thor Odinson"},
  ...
}

Case 2:

var childSchema = new Schema({ name: 'string' });

mongoose.model('children', childSchema);

var parentSchema = new Schema({
  children: {
    type: Schema.Types.ObjectId,
    ref: 'children'
  },
});

In this syntax, child documents will be stored separately, and they reference id (_id) will be stored in the parent document.

Sample documents in this case will look something like this:

// Children documents
{ _id : "childid1" , name : "Captain America"}
{ _id : "childid2" , name : "Iron Man"}
{ _id : "childid3" , name : "Thor Odinson"}

//parent document
{ 
  _id : "parent_random_generated_id"
  children :["childid1","childid2",...],
  child : "childid3",
  ...
}

In the second case you can use Mongodb $lookup operator to populate the sub documents, whenever needed, using mongodb aggregation pipeline, or use .populate('children') or .populate('child') to pupulate the specific child document.

I hope this clarifies your doubt.

Upvotes: 4

Related Questions