Select Matching Array Element and Return Selected Fields

匿名 (未验证) 提交于 2019-12-03 02:43:01

问题:

I would like to know how to set the projection for a matched array of objects from a Mongoose query.

For example, if I have a Mongoose model that looks something like this:

var User = new Schema({   name: String,   children: [Child] });  var Child = new Schema({   name: String,   height: Number,   age: Number,   secret: Number }); 

In other words, an example JSON object that might result from this model:

User: {   name: 'abc',   children: [     {       name: 'def',       height: 123,       age: 7,       secret: 2     },     {       name: 'ghi',       height: 456,       age: 9,       secret: 3     }   ] } 

As you can see the model contains a property children that is an array of Child objects.

If I match only User that contain an item in children that has property name: 'def':

Users.find({   children.name: 'def' }) 

I can then set the projection to select properties (such as name) and also properties from the matched object using a positional operator ($):

.select({   name: 1,   children.$: 1 } 

The problem now is that with this projection, children.$ will always return the entire Child object, including properties I may not want to query, such as secret.

{   name: 'abc',   children: [     {       name: 'def',       height: 123,       age: 7,       secret: 2     }   ] } 

Ideally I would like to be able to also select certain properties from the child object obtained through $ similar to how name was selected from the parent object User, but I cannot find a way to do this.

One way to select a single property is to use the format children.$.age but this can only be used to select 1 property, as doing it multiple times results in an error as you cannot use the poisitional $ operator multiple times.

.select({   name: 1,    // and now select the height and age   // but only of the child that matches name = 'def'   // WITHOUT returning the entire object (exclude name and secret)   children.$.age,   children.$.height // error }) 

Is selecting the projection for an object obtained by the positional operator possible in Mongoose?

回答1:

If you want to only select certain fields of an array to return then you are talking about "reshaping" the document. For anything beyond "basic" field selection, this means using .aggregate() as the method instead of .find().

So the two requirements here are to $filter on the array content to "match" and return, as well as $map the actual "fields to return" from the array itself:

User.aggregate([   { "$match": { "children.name": "def" } },   { "$project": {      "name": 1,      "children": {        "$map": {          "input": {            "$filter": {              "input": "$children",              "as": "c",              "cond": { "$eq": [ "$$c.name", "def" ] }             }          },          "as": "c",          "in": {            "age": "$$c.age",            "height": "$$c.height"          }        }      }   }} ]) 

Here $filter is used in order to reduce the contents of the array down to only those that match the condition. Being those that have the same "name" property as the value "def". This is then passed as the "input" parameter to $map.

The $map operator works just like it's other language counterparts in that it "reshapes arrays" to return something according to what you specify in the "in" parameter. So here we actually only explicitly name the properties and use there variable assignments for the current array element being processed so that these are what are returned as the "new" array content.

The overall result is an array, containing:

  1. Just the items matching the conditions specified.
  2. Just the fields that were specified to return.


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!