{"action":"opened","issue":{"url":"https://api.github.com/repos/Automattic/mongoose/issues/6847","repository_url":"https://api.github.com/repos/Automattic/mongoose","labels_url":"https://api.github.com/repos/Automattic/mongoose/issues/6847/labels{/name}","comments_url":"https://api.github.com/repos/Automattic/mongoose/issues/6847/comments","events_url":"https://api.github.com/repos/Automattic/mongoose/issues/6847/events","html_url":"https://github.com/Automattic/mongoose/issues/6847","id":350020868,"node_id":"MDU6SXNzdWUzNTAwMjA4Njg=","number":6847,"title":"How to update an array of subdocuments using instance methods","user":{"login":"samcoenen","id":20949306,"node_id":"MDQ6VXNlcjIwOTQ5MzA2","avatar_url":"https://avatars3.githubusercontent.com/u/20949306?v=4","gravatar_id":"","url":"https://api.github.com/users/samcoenen","html_url":"https://github.com/samcoenen","followers_url":"https://api.github.com/users/samcoenen/followers","following_url":"https://api.github.com/users/samcoenen/following{/other_user}","gists_url":"https://api.github.com/users/samcoenen/gists{/gist_id}","starred_url":"https://api.github.com/users/samcoenen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/samcoenen/subscriptions","organizations_url":"https://api.github.com/users/samcoenen/orgs","repos_url":"https://api.github.com/users/samcoenen/repos","events_url":"https://api.github.com/users/samcoenen/events{/privacy}","received_events_url":"https://api.github.com/users/samcoenen/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":0,"created_at":"2018-08-13T13:04:14Z","updated_at":"2018-08-13T13:04:14Z","closed_at":null,"author_association":"NONE","body":"**Do you want to request a *feature* or report a *bug*?**\r\nQuestion/Help\r\n\r\n**Short version:**\r\nHow do I translate this\r\n```javascript\r\n// User = mongoose.model('User', UserSchema)\r\nUser.update({ _id: id, 'addresses.primary': true }, { $set: { 'addresses.$.primary': false } });\r\n```\r\ninto a Document instance method?\r\n\r\n\r\n\r\n**Longer, more detailed, version:**\r\n\r\nGiven the schemas:\r\n```javascript\r\nconst AddressSchema = new mongoose.Schema({\r\n  display: { type: String },\r\n  primary: { type: Boolean, default: false },\r\n});\r\n\r\nconst UserSchema = new mongoose.Schema({\r\n  name: { type: String },\r\n  addresses: { type: [AddressSchema], default: [] }\r\n});\r\n```\r\n\r\nImagine I have a user document such as this one:\r\n\r\n```javascript\r\n{\r\n  _id: \"...\",\r\n  name: \"John Doe\",\r\n  addresses: [\r\n    { _id: 1, display: \"Address 1\", primary: true },\r\n    { _id: 2, display: \"Address 2\", primary: false },\r\n    { _id: 3, display: \"Address 3\", primary: true },\r\n  ],\r\n}\r\n```\r\n\r\nWhen adding a new address to the list, I'd like to set all existing address.primary to false.\r\n\r\nNormally I'd do something like:\r\n\r\n```javascript\r\nUserSchema.methods.createAddress = function(address) {\r\n  // First reset every address.primary to false (throws an error)\r\n  this.addresses = this.addresses.map(a => ({ ...a, primary: false });\r\n  this.addresses.push(address);\r\n};\r\n```\r\n\r\nBut this throws an Exception.\r\n```\r\nCast to Array failed for value \"CoreMongooseArray ...\r\n```\r\n\r\nThere's not a lot of documentation on this \"MongooseArray\". E.g. [push](http://mongoosejs.com/docs/api.html#types_array_MongooseArray.push), [unshift](\r\nhttp://mongoosejs.com/docs/api.html#types_array_MongooseArray.unshift) and [addToSet](\r\nhttp://mongoosejs.com/docs/api.html#types_array_MongooseArray.addToSet) as referenced inside the [SubDocuments Documentation](http://mongoosejs.com/docs/subdocs.html) point to nothing.\r\n\r\nAfter looking through the source code I found that MongooseArray uses its' own methods to keep track of changes but I still can't figure out what the correct way is to update my array without Mongoose throwing an error.\r\n\r\nThe following code is untested, but based on the methods it seems like it does the job.\r\n```javascript\r\n// Just need to convert it to a loop\r\nthis.addresses.id(1).set('primary', false);\r\n```\r\n\r\nBut what if I need to update more fields at once instead of just `primary`.\r\n```javascript\r\n// Yikes!\r\nthis.addresses.id(1).set('primary', false);\r\nthis.addresses.id(1).set('inUse', false);\r\nthis.addresses.id(1).set('markedAsSecondary', Date.now());\r\nthis.addresses.id(1).set('markedAsSecondaryBy', 'user-id');\r\n// ...\r\n```\r\n\r\nAm I missing something? This looks overly complicated...\r\nIs there a better way of updating an array of subdocuments using instance methods? Or should I just stick to the query?\r\n\r\n**Please mention your node.js, mongoose and MongoDB version.**\r\nmongoose 5.2.2"}}
{"actor":{"display_login":"samcoenen"}}