This is the third day of my participation in the November Gwen Challenge. Check out the details: the last Gwen Challenge 2021
Mongoose’s Array class extends normal JavaScript arrays with additional Mongoose functionality.
For example, suppose you have a BlogPost model skeleton with an array of tags:
const blogPostSchema = Schema({
title: String.tags: [String]})Copy the code
When you create a new BlogPost document, the Tags attribute is an instance of a normal JavaScript array class. But it also has some special properties.
const blogPostSchema = Schema({
title: String.tags: [String] {},versionKey: false })
const BlogPost = mongoose.model('BlogPost', blogPostSchema)
const doc = new BlogPost({
title: 'Intro to JavaScript'.tags: ['programming']})Array.isArray(doc.tags) // true
doc.tags.isMongooseArray // true
Copy the code
For example, Mongoose intercepts push() calls to the tags array and is smart enough to update the document with $push when you save().
mongoose.set('debug'.true)
doc.tags.push('web development')
// Due to debug mode, print:
// Mongoose: blogposts.updateOne({ _id: ObjectId(...) }, { '$push': { tags: { '$each': [ 'web development' ] } } }, { session: null })
await doc.save()
Copy the code
Document the array
The tags example is a primitive array. Mongoose also supports subdocument arrays. Here’s how to define the Members array, each with firstName and lastName attributes.
const groupSchema = Schema({
name: String.members: [{ firstName: String.lastName: String}]})Copy the code
Doc.members is an instance of a normal JavaScript array, so it has all the usual functions, such as slice() and filter(). But it also has some functions specific to Mongoose.
const groupSchema = Schema({
name: String.members: [{ firstName: String.lastName: String}]})const Group = mongoose.model('Group', groupSchema)
const doc = new Group({
title: 'Jedi Order'.members: [{ firstName: 'Luke'.lastName: 'Skywalker'}]})Array.isArray(doc.members) // true
doc.members.isMongooseArray // true
doc.members.isMongooseDocumentArray // true
Copy the code
For example, if you set firstName for the 0th member, Mongoose will convert it to a collection on member.0.firstName when save() is called.
const groupSchema = Schema({
name: String.members: [{ firstName: String.lastName: String}]}, {versionKey: false })
const Group = mongoose.model('Group', groupSchema)
const doc = new Group({
title: 'Jedi Order'.members: [{ firstName: 'Luke'.lastName: 'Skywalker'}]})await doc.save()
mongoose.set('debug'.true)
doc.members[0].firstName = 'Anakin'
// Mongoose: groups.updateOne({ _id: ObjectId("..." ) }, { '$set': { 'members.0.firstName': 'Anakin' } }, { session: null })
await doc.save()
Copy the code
Considerations when setting an array index
Mongoose has a known problem with setting array indexes directly. For example, if you set doc.tags[0], the Mongoose change trace will not get the change.
const blogPostSchema = Schema({
title: String.tags: [String] {},versionKey: false })
const BlogPost = mongoose.model('BlogPost', blogPostSchema)
const doc = new BlogPost({
title: 'Intro to JavaScript'.tags: ['programming']})await doc.save()
// This change does not end up in the database!
doc.tags[0] = 'JavaScript'
await doc.save()
const fromDb = await BlogPost.findOne({ _id: doc._id })
console.log(fromDb.tags) // ['programming']
Copy the code
To solve this problem, you need to use the markModified() method or explicitly call MongoosearRay.set () on an array element to notify Mongoose of the change trace, as shown below.
// The change worked. Set () is a special way to trigger change tracing on a Mongoose array.
doc.tags.set(0.'JavaScript')
await doc.save()
const fromDb = await BlogPost.findOne({ _id: doc._id })
console.log(fromDb.tags) // ['JavaScript']
Copy the code