Retrieve only the queried element in an object array in MongoDB collection












307
















Suppose you have the following documents in my collection:



{  
"_id":ObjectId("562e7c594c12942f08fe4192"),
"shapes":[
{
"shape":"square",
"color":"blue"
},
{
"shape":"circle",
"color":"red"
}
]
},
{
"_id":ObjectId("562e7c594c12942f08fe4193"),
"shapes":[
{
"shape":"square",
"color":"black"
},
{
"shape":"circle",
"color":"green"
}
]
}




Do query:



db.test.find({"shapes.color": "red"}, {"shapes.color": 1})


Or



db.test.find({shapes: {"$elemMatch": {color: "red"}}}, {"shapes.color": 1})




Returns matched document (Document 1), but always with ALL array items in shapes:



{ "shapes": 
[
{"shape": "square", "color": "blue"},
{"shape": "circle", "color": "red"}
]
}


However, I'd like to get the document (Document 1) only with the array that contains color=red:



{ "shapes": 
[
{"shape": "circle", "color": "red"}
]
}


How can I do this?










share|improve this question





























    307
















    Suppose you have the following documents in my collection:



    {  
    "_id":ObjectId("562e7c594c12942f08fe4192"),
    "shapes":[
    {
    "shape":"square",
    "color":"blue"
    },
    {
    "shape":"circle",
    "color":"red"
    }
    ]
    },
    {
    "_id":ObjectId("562e7c594c12942f08fe4193"),
    "shapes":[
    {
    "shape":"square",
    "color":"black"
    },
    {
    "shape":"circle",
    "color":"green"
    }
    ]
    }




    Do query:



    db.test.find({"shapes.color": "red"}, {"shapes.color": 1})


    Or



    db.test.find({shapes: {"$elemMatch": {color: "red"}}}, {"shapes.color": 1})




    Returns matched document (Document 1), but always with ALL array items in shapes:



    { "shapes": 
    [
    {"shape": "square", "color": "blue"},
    {"shape": "circle", "color": "red"}
    ]
    }


    However, I'd like to get the document (Document 1) only with the array that contains color=red:



    { "shapes": 
    [
    {"shape": "circle", "color": "red"}
    ]
    }


    How can I do this?










    share|improve this question



























      307












      307








      307


      157







      Suppose you have the following documents in my collection:



      {  
      "_id":ObjectId("562e7c594c12942f08fe4192"),
      "shapes":[
      {
      "shape":"square",
      "color":"blue"
      },
      {
      "shape":"circle",
      "color":"red"
      }
      ]
      },
      {
      "_id":ObjectId("562e7c594c12942f08fe4193"),
      "shapes":[
      {
      "shape":"square",
      "color":"black"
      },
      {
      "shape":"circle",
      "color":"green"
      }
      ]
      }




      Do query:



      db.test.find({"shapes.color": "red"}, {"shapes.color": 1})


      Or



      db.test.find({shapes: {"$elemMatch": {color: "red"}}}, {"shapes.color": 1})




      Returns matched document (Document 1), but always with ALL array items in shapes:



      { "shapes": 
      [
      {"shape": "square", "color": "blue"},
      {"shape": "circle", "color": "red"}
      ]
      }


      However, I'd like to get the document (Document 1) only with the array that contains color=red:



      { "shapes": 
      [
      {"shape": "circle", "color": "red"}
      ]
      }


      How can I do this?










      share|improve this question

















      Suppose you have the following documents in my collection:



      {  
      "_id":ObjectId("562e7c594c12942f08fe4192"),
      "shapes":[
      {
      "shape":"square",
      "color":"blue"
      },
      {
      "shape":"circle",
      "color":"red"
      }
      ]
      },
      {
      "_id":ObjectId("562e7c594c12942f08fe4193"),
      "shapes":[
      {
      "shape":"square",
      "color":"black"
      },
      {
      "shape":"circle",
      "color":"green"
      }
      ]
      }




      Do query:



      db.test.find({"shapes.color": "red"}, {"shapes.color": 1})


      Or



      db.test.find({shapes: {"$elemMatch": {color: "red"}}}, {"shapes.color": 1})




      Returns matched document (Document 1), but always with ALL array items in shapes:



      { "shapes": 
      [
      {"shape": "square", "color": "blue"},
      {"shape": "circle", "color": "red"}
      ]
      }


      However, I'd like to get the document (Document 1) only with the array that contains color=red:



      { "shapes": 
      [
      {"shape": "circle", "color": "red"}
      ]
      }


      How can I do this?







      mongodb mongodb-query aggregation-framework projection






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Jan 3 at 6:45









      nabster

      545724




      545724










      asked Oct 21 '10 at 7:31









      SebtmSebtm

      2,72262430




      2,72262430
























          11 Answers
          11






          active

          oldest

          votes


















          336














          MongoDB 2.2's new $elemMatch projection operator provides another way to alter the returned document to contain only the first matched shapes element:





          db.test.find(
          {"shapes.color": "red"},
          {_id: 0, shapes: {$elemMatch: {color: "red"}}});


          Returns:



          {"shapes" : [{"shape": "circle", "color": "red"}]}


          In 2.2 you can also do this using the $ projection operator, where the $ in a projection object field name represents the index of the field's first matching array element from the query. The following returns the same results as above:



          db.test.find({"shapes.color": "red"}, {_id: 0, 'shapes.$': 1});


          MongoDB 3.2 Update



          Starting with the 3.2 release, you can use the new $filter aggregation operator to filter an array during projection, which has the benefit of including all matches, instead of just the first one.



          db.test.aggregate([
          // Get just the docs that contain a shapes element where color is 'red'
          {$match: {'shapes.color': 'red'}},
          {$project: {
          shapes: {$filter: {
          input: '$shapes',
          as: 'shape',
          cond: {$eq: ['$$shape.color', 'red']}
          }},
          _id: 0
          }}
          ])


          Results:



          [ 
          {
          "shapes" : [
          {
          "shape" : "circle",
          "color" : "red"
          }
          ]
          }
          ]





          share|improve this answer



















          • 58




            Note that as the documentation tells you both $elemMatch and $ only return the first match.
            – kynan
            Feb 3 '13 at 0:26






          • 12




            any solution if I want it to return every elements that matches it instead of just the first?
            – Steve Ng
            Dec 25 '13 at 8:12










          • @JohnnyHK, yup, i used it eventually, thanks!
            – Steve Ng
            Dec 26 '13 at 6:19










          • but this just returns the first matched element!
            – charliebrownie
            Jan 10 '16 at 20:18






          • 1




            @charliebrownie See the option using $filter to get all matches.
            – JohnnyHK
            Jan 10 '16 at 20:29



















          93














          The new Aggregation Framework in MongoDB 2.2+ provides an alternative to Map/Reduce. The $unwind operator can be used to separate your shapes array into a stream of documents that can be matched:



          db.test.aggregate(
          // Start with a $match pipeline which can take advantage of an index and limit documents processed
          { $match : {
          "shapes.color": "red"
          }},
          { $unwind : "$shapes" },
          { $match : {
          "shapes.color": "red"
          }}
          )


          Results in:



          {
          "result" : [
          {
          "_id" : ObjectId("504425059b7c9fa7ec92beec"),
          "shapes" : {
          "shape" : "circle",
          "color" : "red"
          }
          }
          ],
          "ok" : 1
          }





          share|improve this answer



















          • 6




            @JohnnyHK: In this case, $elemMatch is another option. I actually got here by way of a Google Group question where $elemMatch wouldn't work because it only returns the first match per document.
            – Stennie
            Sep 3 '12 at 4:24






          • 1




            Thanks, I wasn't aware of that limitation so that's good to know. Sorry for deleting my comment you're responding to, I decided to post another answer instead and didn't want to confuse people.
            – JohnnyHK
            Sep 3 '12 at 4:35








          • 3




            @JohnnyHK: No worries, there are now three useful answers for the question ;-)
            – Stennie
            Sep 3 '12 at 4:41










          • For other searchers, in addition to this I also tried adding { $project : { shapes : 1 } } - which seemed to work and would be helpful if the enclosing documents were large and you just wanted to view the shapes key values.
            – user1063287
            Dec 4 '14 at 8:23








          • 2




            @calmbird I updated the example to include an initial $match stage. If you're interested in a more efficient feature suggestion I would watch/upvote SERVER-6612: Support projecting multiple array values in a projection like the $elemMatch projection specifier in the MongoDB issue tracker.
            – Stennie
            Jan 28 '15 at 8:52



















          28















          Caution: This answer provides a solution that was relevant at that time, before the new features of MongoDB 2.2 and up were introduced. See the other answers if you are using a more recent version of MongoDB.




          The field selector parameter is limited to complete properties. It cannot be used to select part of an array, only the entire array. I tried using the $ positional operator, but that didn't work.



          The easiest way is to just filter the shapes in the client.



          If you really need the correct output directly from MongoDB, you can use a map-reduce to filter the shapes.



          function map() {
          filteredShapes = ;

          this.shapes.forEach(function (s) {
          if (s.color === "red") {
          filteredShapes.push(s);
          }
          });

          emit(this._id, { shapes: filteredShapes });
          }

          function reduce(key, values) {
          return values[0];
          }

          res = db.test.mapReduce(map, reduce, { query: { "shapes.color": "red" } })

          db[res.result].find()





          share|improve this answer































            27














            Another interesing way is to use $redact, which is one of the new aggregation features of MongoDB 2.6. If you are using 2.6, you don't need an $unwind which might cause you performance problems if you have large arrays.



            db.test.aggregate([
            { $match: {
            shapes: { $elemMatch: {color: "red"} }
            }},
            { $redact : {
            $cond: {
            if: { $or : [{ $eq: ["$color","red"] }, { $not : "$color" }]},
            then: "$$DESCEND",
            else: "$$PRUNE"
            }
            }}]);


            $redact "restricts the contents of the documents based on information stored in the documents themselves". So it will run only inside of the document. It basically scans your document top to the bottom, and checks if it matches with your if condition which is in $cond, if there is match it will either keep the content($$DESCEND) or remove($$PRUNE).



            In the example above, first $match returns the whole shapes array, and $redact strips it down to the expected result.



            Note that {$not:"$color"} is necessary, because it will scan the top document as well, and if $redact does not find a color field on the top level this will return false that might strip the whole document which we don't want.






            share|improve this answer

















            • 1




              perfect answer. As you mentioned $unwind will consume lot of RAM. So this will be better when compared.
              – manojpt
              Apr 21 '15 at 11:21










            • I have a doubt. In the example, "shapes" is an array. Will "$redact" scan all the objects in the "shapes" array ?? How this will be good with respect to performance??
              – manojpt
              Apr 23 '15 at 8:13












            • not all of it, but the result of your first match. That is the reason why you put $match as your first aggregate stage
              – anvarik
              Apr 23 '15 at 16:36










            • okkk.. if an index created on "color" field, even then it will scan all the objects in the "shapes" array??? Which could be the efficient way of matching multiple objects in an array???
              – manojpt
              Apr 24 '15 at 4:47






            • 2




              Brilliant! I do not understand how $eq works here. I left it off originally and this didn't work for me. Somehow, it looks in the array of shapes to find the match, but the query never specifies which array to look in. Like, if the documents had shapes and, for example, sizes; would $eq look in both arrays for matches? Is $redact just looking for anything within the document that matches the 'if' condition?
              – Onosa
              Dec 30 '15 at 14:46



















            18














            Better you can query in matching array element using $slice is it helpful to returning the significant object in an array.



            db.test.find({"shapes.color" : "blue"}, {"shapes.$" : 1})


            $slice is helpful when you know the index of the element, but sometimes you want
            whichever array element matched your criteria. You can return the matching element
            with the $ operator.






            share|improve this answer































              11














              The syntax for find in mongodb is



                  db.<collection name>.find(query, projection);


              and the second query that you have written, that is



                  db.test.find(
              {shapes: {"$elemMatch": {color: "red"}}},
              {"shapes.color":1})


              in this you have used the $elemMatch operator in query part, whereas if you use this operator in the projection part then you will get the desired result. You can write down your query as



                   db.users.find(
              {"shapes.color":"red"},
              {_id:0, shapes: {$elemMatch : {color: "red"}}})


              This will give you the desired result.






              share|improve this answer



















              • 1




                This works for me. However, It appears that "shapes.color":"red" in the query parameter (the first parameter of the find method) is not necessary. You can replace it with {} and get the same results.
                – Erik Olson
                May 9 '14 at 20:35






              • 2




                @ErikOlson Your suggestion is right in the above case, where we need to find all the document that with red color and to apply the projection on them only. But let's say if somebody requires to find out all the document that have color blue but it should return only those element of that shapes array that have color red. In this case the above query can be referenced by somebody else also..
                – Vicky
                May 11 '14 at 9:22










              • This seems to be the easiest, but I can't make it work it. It only returns the first matching subdocument.
                – newman
                Aug 29 '15 at 23:05



















              11














               db.getCollection('aj').find({"shapes.color":"red"},{"shapes.$":1})


              OUTPUTS



              {

              "shapes" : [
              {
              "shape" : "circle",
              "color" : "red"
              }
              ]
              }





              share|improve this answer





























                7














                Thanks to JohnnyHK.



                Here I just want to add some more complex usage.



                // Document 
                {
                "_id" : 1
                "shapes" : [
                {"shape" : "square", "color" : "red"},
                {"shape" : "circle", "color" : "green"}
                ]
                }

                {
                "_id" : 2
                "shapes" : [
                {"shape" : "square", "color" : "red"},
                {"shape" : "circle", "color" : "green"}
                ]
                }


                // The Query
                db.contents.find({
                "_id" : ObjectId(1),
                "shapes.color":"red"
                },{
                "_id": 0,
                "shapes" :{
                "$elemMatch":{
                "color" : "red"
                }
                }
                })


                //And the Result

                {"shapes":[
                {
                "shape" : "square",
                "color" : "red"
                }
                ]}





                share|improve this answer































                  5














                  You just need to run query



                  db.test.find(
                  {"shapes.color": "red"},
                  {shapes: {$elemMatch: {color: "red"}}});


                  output of this query is



                  {
                  "_id" : ObjectId("562e7c594c12942f08fe4192"),
                  "shapes" : [
                  {"shape" : "circle", "color" : "red"}
                  ]
                  }


                  as you expected it'll gives the exact field from array that matches color:'red'.






                  share|improve this answer































                    2














                    along with $project it will be more appropriate other wise matching elements will be clubbed together with other elements in document.



                    db.test.aggregate(
                    { "$unwind" : "$shapes" },
                    { "$match" : {
                    "shapes.color": "red"
                    }},
                    {"$project":{
                    "_id":1,
                    "item":1
                    }}
                    )





                    share|improve this answer





















                    • can you pls describe that this accomplishes with an input and output set?
                      – Alexander Mills
                      Nov 24 '15 at 17:13



















                    0














                    db.test.find( {"shapes.color": "red"}, {_id: 0})





                    share|improve this answer



















                    • 1




                      Welcome to Stack Overflow! Thank you for the code snippet, which might provide some limited, immediate help. A proper explanation would greatly improve its long-term value by describing why this is a good solution to the problem, and would make it more useful to future readers with other similar questions. Please edit your answer to add some explanation, including the assumptions you've made.
                      – sepehr
                      Oct 25 '18 at 15:06










                    protected by Samuel Liew Oct 5 '15 at 9:21



                    Thank you for your interest in this question.
                    Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).



                    Would you like to answer one of these unanswered questions instead?














                    11 Answers
                    11






                    active

                    oldest

                    votes








                    11 Answers
                    11






                    active

                    oldest

                    votes









                    active

                    oldest

                    votes






                    active

                    oldest

                    votes









                    336














                    MongoDB 2.2's new $elemMatch projection operator provides another way to alter the returned document to contain only the first matched shapes element:





                    db.test.find(
                    {"shapes.color": "red"},
                    {_id: 0, shapes: {$elemMatch: {color: "red"}}});


                    Returns:



                    {"shapes" : [{"shape": "circle", "color": "red"}]}


                    In 2.2 you can also do this using the $ projection operator, where the $ in a projection object field name represents the index of the field's first matching array element from the query. The following returns the same results as above:



                    db.test.find({"shapes.color": "red"}, {_id: 0, 'shapes.$': 1});


                    MongoDB 3.2 Update



                    Starting with the 3.2 release, you can use the new $filter aggregation operator to filter an array during projection, which has the benefit of including all matches, instead of just the first one.



                    db.test.aggregate([
                    // Get just the docs that contain a shapes element where color is 'red'
                    {$match: {'shapes.color': 'red'}},
                    {$project: {
                    shapes: {$filter: {
                    input: '$shapes',
                    as: 'shape',
                    cond: {$eq: ['$$shape.color', 'red']}
                    }},
                    _id: 0
                    }}
                    ])


                    Results:



                    [ 
                    {
                    "shapes" : [
                    {
                    "shape" : "circle",
                    "color" : "red"
                    }
                    ]
                    }
                    ]





                    share|improve this answer



















                    • 58




                      Note that as the documentation tells you both $elemMatch and $ only return the first match.
                      – kynan
                      Feb 3 '13 at 0:26






                    • 12




                      any solution if I want it to return every elements that matches it instead of just the first?
                      – Steve Ng
                      Dec 25 '13 at 8:12










                    • @JohnnyHK, yup, i used it eventually, thanks!
                      – Steve Ng
                      Dec 26 '13 at 6:19










                    • but this just returns the first matched element!
                      – charliebrownie
                      Jan 10 '16 at 20:18






                    • 1




                      @charliebrownie See the option using $filter to get all matches.
                      – JohnnyHK
                      Jan 10 '16 at 20:29
















                    336














                    MongoDB 2.2's new $elemMatch projection operator provides another way to alter the returned document to contain only the first matched shapes element:





                    db.test.find(
                    {"shapes.color": "red"},
                    {_id: 0, shapes: {$elemMatch: {color: "red"}}});


                    Returns:



                    {"shapes" : [{"shape": "circle", "color": "red"}]}


                    In 2.2 you can also do this using the $ projection operator, where the $ in a projection object field name represents the index of the field's first matching array element from the query. The following returns the same results as above:



                    db.test.find({"shapes.color": "red"}, {_id: 0, 'shapes.$': 1});


                    MongoDB 3.2 Update



                    Starting with the 3.2 release, you can use the new $filter aggregation operator to filter an array during projection, which has the benefit of including all matches, instead of just the first one.



                    db.test.aggregate([
                    // Get just the docs that contain a shapes element where color is 'red'
                    {$match: {'shapes.color': 'red'}},
                    {$project: {
                    shapes: {$filter: {
                    input: '$shapes',
                    as: 'shape',
                    cond: {$eq: ['$$shape.color', 'red']}
                    }},
                    _id: 0
                    }}
                    ])


                    Results:



                    [ 
                    {
                    "shapes" : [
                    {
                    "shape" : "circle",
                    "color" : "red"
                    }
                    ]
                    }
                    ]





                    share|improve this answer



















                    • 58




                      Note that as the documentation tells you both $elemMatch and $ only return the first match.
                      – kynan
                      Feb 3 '13 at 0:26






                    • 12




                      any solution if I want it to return every elements that matches it instead of just the first?
                      – Steve Ng
                      Dec 25 '13 at 8:12










                    • @JohnnyHK, yup, i used it eventually, thanks!
                      – Steve Ng
                      Dec 26 '13 at 6:19










                    • but this just returns the first matched element!
                      – charliebrownie
                      Jan 10 '16 at 20:18






                    • 1




                      @charliebrownie See the option using $filter to get all matches.
                      – JohnnyHK
                      Jan 10 '16 at 20:29














                    336












                    336








                    336






                    MongoDB 2.2's new $elemMatch projection operator provides another way to alter the returned document to contain only the first matched shapes element:





                    db.test.find(
                    {"shapes.color": "red"},
                    {_id: 0, shapes: {$elemMatch: {color: "red"}}});


                    Returns:



                    {"shapes" : [{"shape": "circle", "color": "red"}]}


                    In 2.2 you can also do this using the $ projection operator, where the $ in a projection object field name represents the index of the field's first matching array element from the query. The following returns the same results as above:



                    db.test.find({"shapes.color": "red"}, {_id: 0, 'shapes.$': 1});


                    MongoDB 3.2 Update



                    Starting with the 3.2 release, you can use the new $filter aggregation operator to filter an array during projection, which has the benefit of including all matches, instead of just the first one.



                    db.test.aggregate([
                    // Get just the docs that contain a shapes element where color is 'red'
                    {$match: {'shapes.color': 'red'}},
                    {$project: {
                    shapes: {$filter: {
                    input: '$shapes',
                    as: 'shape',
                    cond: {$eq: ['$$shape.color', 'red']}
                    }},
                    _id: 0
                    }}
                    ])


                    Results:



                    [ 
                    {
                    "shapes" : [
                    {
                    "shape" : "circle",
                    "color" : "red"
                    }
                    ]
                    }
                    ]





                    share|improve this answer














                    MongoDB 2.2's new $elemMatch projection operator provides another way to alter the returned document to contain only the first matched shapes element:





                    db.test.find(
                    {"shapes.color": "red"},
                    {_id: 0, shapes: {$elemMatch: {color: "red"}}});


                    Returns:



                    {"shapes" : [{"shape": "circle", "color": "red"}]}


                    In 2.2 you can also do this using the $ projection operator, where the $ in a projection object field name represents the index of the field's first matching array element from the query. The following returns the same results as above:



                    db.test.find({"shapes.color": "red"}, {_id: 0, 'shapes.$': 1});


                    MongoDB 3.2 Update



                    Starting with the 3.2 release, you can use the new $filter aggregation operator to filter an array during projection, which has the benefit of including all matches, instead of just the first one.



                    db.test.aggregate([
                    // Get just the docs that contain a shapes element where color is 'red'
                    {$match: {'shapes.color': 'red'}},
                    {$project: {
                    shapes: {$filter: {
                    input: '$shapes',
                    as: 'shape',
                    cond: {$eq: ['$$shape.color', 'red']}
                    }},
                    _id: 0
                    }}
                    ])


                    Results:



                    [ 
                    {
                    "shapes" : [
                    {
                    "shape" : "circle",
                    "color" : "red"
                    }
                    ]
                    }
                    ]






                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    edited Sep 25 '18 at 18:04









                    Faraz Durrani

                    2,6562934




                    2,6562934










                    answered Sep 3 '12 at 4:19









                    JohnnyHKJohnnyHK

                    206k38438363




                    206k38438363








                    • 58




                      Note that as the documentation tells you both $elemMatch and $ only return the first match.
                      – kynan
                      Feb 3 '13 at 0:26






                    • 12




                      any solution if I want it to return every elements that matches it instead of just the first?
                      – Steve Ng
                      Dec 25 '13 at 8:12










                    • @JohnnyHK, yup, i used it eventually, thanks!
                      – Steve Ng
                      Dec 26 '13 at 6:19










                    • but this just returns the first matched element!
                      – charliebrownie
                      Jan 10 '16 at 20:18






                    • 1




                      @charliebrownie See the option using $filter to get all matches.
                      – JohnnyHK
                      Jan 10 '16 at 20:29














                    • 58




                      Note that as the documentation tells you both $elemMatch and $ only return the first match.
                      – kynan
                      Feb 3 '13 at 0:26






                    • 12




                      any solution if I want it to return every elements that matches it instead of just the first?
                      – Steve Ng
                      Dec 25 '13 at 8:12










                    • @JohnnyHK, yup, i used it eventually, thanks!
                      – Steve Ng
                      Dec 26 '13 at 6:19










                    • but this just returns the first matched element!
                      – charliebrownie
                      Jan 10 '16 at 20:18






                    • 1




                      @charliebrownie See the option using $filter to get all matches.
                      – JohnnyHK
                      Jan 10 '16 at 20:29








                    58




                    58




                    Note that as the documentation tells you both $elemMatch and $ only return the first match.
                    – kynan
                    Feb 3 '13 at 0:26




                    Note that as the documentation tells you both $elemMatch and $ only return the first match.
                    – kynan
                    Feb 3 '13 at 0:26




                    12




                    12




                    any solution if I want it to return every elements that matches it instead of just the first?
                    – Steve Ng
                    Dec 25 '13 at 8:12




                    any solution if I want it to return every elements that matches it instead of just the first?
                    – Steve Ng
                    Dec 25 '13 at 8:12












                    @JohnnyHK, yup, i used it eventually, thanks!
                    – Steve Ng
                    Dec 26 '13 at 6:19




                    @JohnnyHK, yup, i used it eventually, thanks!
                    – Steve Ng
                    Dec 26 '13 at 6:19












                    but this just returns the first matched element!
                    – charliebrownie
                    Jan 10 '16 at 20:18




                    but this just returns the first matched element!
                    – charliebrownie
                    Jan 10 '16 at 20:18




                    1




                    1




                    @charliebrownie See the option using $filter to get all matches.
                    – JohnnyHK
                    Jan 10 '16 at 20:29




                    @charliebrownie See the option using $filter to get all matches.
                    – JohnnyHK
                    Jan 10 '16 at 20:29













                    93














                    The new Aggregation Framework in MongoDB 2.2+ provides an alternative to Map/Reduce. The $unwind operator can be used to separate your shapes array into a stream of documents that can be matched:



                    db.test.aggregate(
                    // Start with a $match pipeline which can take advantage of an index and limit documents processed
                    { $match : {
                    "shapes.color": "red"
                    }},
                    { $unwind : "$shapes" },
                    { $match : {
                    "shapes.color": "red"
                    }}
                    )


                    Results in:



                    {
                    "result" : [
                    {
                    "_id" : ObjectId("504425059b7c9fa7ec92beec"),
                    "shapes" : {
                    "shape" : "circle",
                    "color" : "red"
                    }
                    }
                    ],
                    "ok" : 1
                    }





                    share|improve this answer



















                    • 6




                      @JohnnyHK: In this case, $elemMatch is another option. I actually got here by way of a Google Group question where $elemMatch wouldn't work because it only returns the first match per document.
                      – Stennie
                      Sep 3 '12 at 4:24






                    • 1




                      Thanks, I wasn't aware of that limitation so that's good to know. Sorry for deleting my comment you're responding to, I decided to post another answer instead and didn't want to confuse people.
                      – JohnnyHK
                      Sep 3 '12 at 4:35








                    • 3




                      @JohnnyHK: No worries, there are now three useful answers for the question ;-)
                      – Stennie
                      Sep 3 '12 at 4:41










                    • For other searchers, in addition to this I also tried adding { $project : { shapes : 1 } } - which seemed to work and would be helpful if the enclosing documents were large and you just wanted to view the shapes key values.
                      – user1063287
                      Dec 4 '14 at 8:23








                    • 2




                      @calmbird I updated the example to include an initial $match stage. If you're interested in a more efficient feature suggestion I would watch/upvote SERVER-6612: Support projecting multiple array values in a projection like the $elemMatch projection specifier in the MongoDB issue tracker.
                      – Stennie
                      Jan 28 '15 at 8:52
















                    93














                    The new Aggregation Framework in MongoDB 2.2+ provides an alternative to Map/Reduce. The $unwind operator can be used to separate your shapes array into a stream of documents that can be matched:



                    db.test.aggregate(
                    // Start with a $match pipeline which can take advantage of an index and limit documents processed
                    { $match : {
                    "shapes.color": "red"
                    }},
                    { $unwind : "$shapes" },
                    { $match : {
                    "shapes.color": "red"
                    }}
                    )


                    Results in:



                    {
                    "result" : [
                    {
                    "_id" : ObjectId("504425059b7c9fa7ec92beec"),
                    "shapes" : {
                    "shape" : "circle",
                    "color" : "red"
                    }
                    }
                    ],
                    "ok" : 1
                    }





                    share|improve this answer



















                    • 6




                      @JohnnyHK: In this case, $elemMatch is another option. I actually got here by way of a Google Group question where $elemMatch wouldn't work because it only returns the first match per document.
                      – Stennie
                      Sep 3 '12 at 4:24






                    • 1




                      Thanks, I wasn't aware of that limitation so that's good to know. Sorry for deleting my comment you're responding to, I decided to post another answer instead and didn't want to confuse people.
                      – JohnnyHK
                      Sep 3 '12 at 4:35








                    • 3




                      @JohnnyHK: No worries, there are now three useful answers for the question ;-)
                      – Stennie
                      Sep 3 '12 at 4:41










                    • For other searchers, in addition to this I also tried adding { $project : { shapes : 1 } } - which seemed to work and would be helpful if the enclosing documents were large and you just wanted to view the shapes key values.
                      – user1063287
                      Dec 4 '14 at 8:23








                    • 2




                      @calmbird I updated the example to include an initial $match stage. If you're interested in a more efficient feature suggestion I would watch/upvote SERVER-6612: Support projecting multiple array values in a projection like the $elemMatch projection specifier in the MongoDB issue tracker.
                      – Stennie
                      Jan 28 '15 at 8:52














                    93












                    93








                    93






                    The new Aggregation Framework in MongoDB 2.2+ provides an alternative to Map/Reduce. The $unwind operator can be used to separate your shapes array into a stream of documents that can be matched:



                    db.test.aggregate(
                    // Start with a $match pipeline which can take advantage of an index and limit documents processed
                    { $match : {
                    "shapes.color": "red"
                    }},
                    { $unwind : "$shapes" },
                    { $match : {
                    "shapes.color": "red"
                    }}
                    )


                    Results in:



                    {
                    "result" : [
                    {
                    "_id" : ObjectId("504425059b7c9fa7ec92beec"),
                    "shapes" : {
                    "shape" : "circle",
                    "color" : "red"
                    }
                    }
                    ],
                    "ok" : 1
                    }





                    share|improve this answer














                    The new Aggregation Framework in MongoDB 2.2+ provides an alternative to Map/Reduce. The $unwind operator can be used to separate your shapes array into a stream of documents that can be matched:



                    db.test.aggregate(
                    // Start with a $match pipeline which can take advantage of an index and limit documents processed
                    { $match : {
                    "shapes.color": "red"
                    }},
                    { $unwind : "$shapes" },
                    { $match : {
                    "shapes.color": "red"
                    }}
                    )


                    Results in:



                    {
                    "result" : [
                    {
                    "_id" : ObjectId("504425059b7c9fa7ec92beec"),
                    "shapes" : {
                    "shape" : "circle",
                    "color" : "red"
                    }
                    }
                    ],
                    "ok" : 1
                    }






                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    edited Jan 28 '15 at 8:41

























                    answered Sep 3 '12 at 3:44









                    StennieStennie

                    46.2k8109138




                    46.2k8109138








                    • 6




                      @JohnnyHK: In this case, $elemMatch is another option. I actually got here by way of a Google Group question where $elemMatch wouldn't work because it only returns the first match per document.
                      – Stennie
                      Sep 3 '12 at 4:24






                    • 1




                      Thanks, I wasn't aware of that limitation so that's good to know. Sorry for deleting my comment you're responding to, I decided to post another answer instead and didn't want to confuse people.
                      – JohnnyHK
                      Sep 3 '12 at 4:35








                    • 3




                      @JohnnyHK: No worries, there are now three useful answers for the question ;-)
                      – Stennie
                      Sep 3 '12 at 4:41










                    • For other searchers, in addition to this I also tried adding { $project : { shapes : 1 } } - which seemed to work and would be helpful if the enclosing documents were large and you just wanted to view the shapes key values.
                      – user1063287
                      Dec 4 '14 at 8:23








                    • 2




                      @calmbird I updated the example to include an initial $match stage. If you're interested in a more efficient feature suggestion I would watch/upvote SERVER-6612: Support projecting multiple array values in a projection like the $elemMatch projection specifier in the MongoDB issue tracker.
                      – Stennie
                      Jan 28 '15 at 8:52














                    • 6




                      @JohnnyHK: In this case, $elemMatch is another option. I actually got here by way of a Google Group question where $elemMatch wouldn't work because it only returns the first match per document.
                      – Stennie
                      Sep 3 '12 at 4:24






                    • 1




                      Thanks, I wasn't aware of that limitation so that's good to know. Sorry for deleting my comment you're responding to, I decided to post another answer instead and didn't want to confuse people.
                      – JohnnyHK
                      Sep 3 '12 at 4:35








                    • 3




                      @JohnnyHK: No worries, there are now three useful answers for the question ;-)
                      – Stennie
                      Sep 3 '12 at 4:41










                    • For other searchers, in addition to this I also tried adding { $project : { shapes : 1 } } - which seemed to work and would be helpful if the enclosing documents were large and you just wanted to view the shapes key values.
                      – user1063287
                      Dec 4 '14 at 8:23








                    • 2




                      @calmbird I updated the example to include an initial $match stage. If you're interested in a more efficient feature suggestion I would watch/upvote SERVER-6612: Support projecting multiple array values in a projection like the $elemMatch projection specifier in the MongoDB issue tracker.
                      – Stennie
                      Jan 28 '15 at 8:52








                    6




                    6




                    @JohnnyHK: In this case, $elemMatch is another option. I actually got here by way of a Google Group question where $elemMatch wouldn't work because it only returns the first match per document.
                    – Stennie
                    Sep 3 '12 at 4:24




                    @JohnnyHK: In this case, $elemMatch is another option. I actually got here by way of a Google Group question where $elemMatch wouldn't work because it only returns the first match per document.
                    – Stennie
                    Sep 3 '12 at 4:24




                    1




                    1




                    Thanks, I wasn't aware of that limitation so that's good to know. Sorry for deleting my comment you're responding to, I decided to post another answer instead and didn't want to confuse people.
                    – JohnnyHK
                    Sep 3 '12 at 4:35






                    Thanks, I wasn't aware of that limitation so that's good to know. Sorry for deleting my comment you're responding to, I decided to post another answer instead and didn't want to confuse people.
                    – JohnnyHK
                    Sep 3 '12 at 4:35






                    3




                    3




                    @JohnnyHK: No worries, there are now three useful answers for the question ;-)
                    – Stennie
                    Sep 3 '12 at 4:41




                    @JohnnyHK: No worries, there are now three useful answers for the question ;-)
                    – Stennie
                    Sep 3 '12 at 4:41












                    For other searchers, in addition to this I also tried adding { $project : { shapes : 1 } } - which seemed to work and would be helpful if the enclosing documents were large and you just wanted to view the shapes key values.
                    – user1063287
                    Dec 4 '14 at 8:23






                    For other searchers, in addition to this I also tried adding { $project : { shapes : 1 } } - which seemed to work and would be helpful if the enclosing documents were large and you just wanted to view the shapes key values.
                    – user1063287
                    Dec 4 '14 at 8:23






                    2




                    2




                    @calmbird I updated the example to include an initial $match stage. If you're interested in a more efficient feature suggestion I would watch/upvote SERVER-6612: Support projecting multiple array values in a projection like the $elemMatch projection specifier in the MongoDB issue tracker.
                    – Stennie
                    Jan 28 '15 at 8:52




                    @calmbird I updated the example to include an initial $match stage. If you're interested in a more efficient feature suggestion I would watch/upvote SERVER-6612: Support projecting multiple array values in a projection like the $elemMatch projection specifier in the MongoDB issue tracker.
                    – Stennie
                    Jan 28 '15 at 8:52











                    28















                    Caution: This answer provides a solution that was relevant at that time, before the new features of MongoDB 2.2 and up were introduced. See the other answers if you are using a more recent version of MongoDB.




                    The field selector parameter is limited to complete properties. It cannot be used to select part of an array, only the entire array. I tried using the $ positional operator, but that didn't work.



                    The easiest way is to just filter the shapes in the client.



                    If you really need the correct output directly from MongoDB, you can use a map-reduce to filter the shapes.



                    function map() {
                    filteredShapes = ;

                    this.shapes.forEach(function (s) {
                    if (s.color === "red") {
                    filteredShapes.push(s);
                    }
                    });

                    emit(this._id, { shapes: filteredShapes });
                    }

                    function reduce(key, values) {
                    return values[0];
                    }

                    res = db.test.mapReduce(map, reduce, { query: { "shapes.color": "red" } })

                    db[res.result].find()





                    share|improve this answer




























                      28















                      Caution: This answer provides a solution that was relevant at that time, before the new features of MongoDB 2.2 and up were introduced. See the other answers if you are using a more recent version of MongoDB.




                      The field selector parameter is limited to complete properties. It cannot be used to select part of an array, only the entire array. I tried using the $ positional operator, but that didn't work.



                      The easiest way is to just filter the shapes in the client.



                      If you really need the correct output directly from MongoDB, you can use a map-reduce to filter the shapes.



                      function map() {
                      filteredShapes = ;

                      this.shapes.forEach(function (s) {
                      if (s.color === "red") {
                      filteredShapes.push(s);
                      }
                      });

                      emit(this._id, { shapes: filteredShapes });
                      }

                      function reduce(key, values) {
                      return values[0];
                      }

                      res = db.test.mapReduce(map, reduce, { query: { "shapes.color": "red" } })

                      db[res.result].find()





                      share|improve this answer


























                        28












                        28








                        28







                        Caution: This answer provides a solution that was relevant at that time, before the new features of MongoDB 2.2 and up were introduced. See the other answers if you are using a more recent version of MongoDB.




                        The field selector parameter is limited to complete properties. It cannot be used to select part of an array, only the entire array. I tried using the $ positional operator, but that didn't work.



                        The easiest way is to just filter the shapes in the client.



                        If you really need the correct output directly from MongoDB, you can use a map-reduce to filter the shapes.



                        function map() {
                        filteredShapes = ;

                        this.shapes.forEach(function (s) {
                        if (s.color === "red") {
                        filteredShapes.push(s);
                        }
                        });

                        emit(this._id, { shapes: filteredShapes });
                        }

                        function reduce(key, values) {
                        return values[0];
                        }

                        res = db.test.mapReduce(map, reduce, { query: { "shapes.color": "red" } })

                        db[res.result].find()





                        share|improve this answer















                        Caution: This answer provides a solution that was relevant at that time, before the new features of MongoDB 2.2 and up were introduced. See the other answers if you are using a more recent version of MongoDB.




                        The field selector parameter is limited to complete properties. It cannot be used to select part of an array, only the entire array. I tried using the $ positional operator, but that didn't work.



                        The easiest way is to just filter the shapes in the client.



                        If you really need the correct output directly from MongoDB, you can use a map-reduce to filter the shapes.



                        function map() {
                        filteredShapes = ;

                        this.shapes.forEach(function (s) {
                        if (s.color === "red") {
                        filteredShapes.push(s);
                        }
                        });

                        emit(this._id, { shapes: filteredShapes });
                        }

                        function reduce(key, values) {
                        return values[0];
                        }

                        res = db.test.mapReduce(map, reduce, { query: { "shapes.color": "red" } })

                        db[res.result].find()






                        share|improve this answer














                        share|improve this answer



                        share|improve this answer








                        edited Jul 19 '16 at 18:42

























                        answered Oct 21 '10 at 9:25









                        Niels van der RestNiels van der Rest

                        22.9k137182




                        22.9k137182























                            27














                            Another interesing way is to use $redact, which is one of the new aggregation features of MongoDB 2.6. If you are using 2.6, you don't need an $unwind which might cause you performance problems if you have large arrays.



                            db.test.aggregate([
                            { $match: {
                            shapes: { $elemMatch: {color: "red"} }
                            }},
                            { $redact : {
                            $cond: {
                            if: { $or : [{ $eq: ["$color","red"] }, { $not : "$color" }]},
                            then: "$$DESCEND",
                            else: "$$PRUNE"
                            }
                            }}]);


                            $redact "restricts the contents of the documents based on information stored in the documents themselves". So it will run only inside of the document. It basically scans your document top to the bottom, and checks if it matches with your if condition which is in $cond, if there is match it will either keep the content($$DESCEND) or remove($$PRUNE).



                            In the example above, first $match returns the whole shapes array, and $redact strips it down to the expected result.



                            Note that {$not:"$color"} is necessary, because it will scan the top document as well, and if $redact does not find a color field on the top level this will return false that might strip the whole document which we don't want.






                            share|improve this answer

















                            • 1




                              perfect answer. As you mentioned $unwind will consume lot of RAM. So this will be better when compared.
                              – manojpt
                              Apr 21 '15 at 11:21










                            • I have a doubt. In the example, "shapes" is an array. Will "$redact" scan all the objects in the "shapes" array ?? How this will be good with respect to performance??
                              – manojpt
                              Apr 23 '15 at 8:13












                            • not all of it, but the result of your first match. That is the reason why you put $match as your first aggregate stage
                              – anvarik
                              Apr 23 '15 at 16:36










                            • okkk.. if an index created on "color" field, even then it will scan all the objects in the "shapes" array??? Which could be the efficient way of matching multiple objects in an array???
                              – manojpt
                              Apr 24 '15 at 4:47






                            • 2




                              Brilliant! I do not understand how $eq works here. I left it off originally and this didn't work for me. Somehow, it looks in the array of shapes to find the match, but the query never specifies which array to look in. Like, if the documents had shapes and, for example, sizes; would $eq look in both arrays for matches? Is $redact just looking for anything within the document that matches the 'if' condition?
                              – Onosa
                              Dec 30 '15 at 14:46
















                            27














                            Another interesing way is to use $redact, which is one of the new aggregation features of MongoDB 2.6. If you are using 2.6, you don't need an $unwind which might cause you performance problems if you have large arrays.



                            db.test.aggregate([
                            { $match: {
                            shapes: { $elemMatch: {color: "red"} }
                            }},
                            { $redact : {
                            $cond: {
                            if: { $or : [{ $eq: ["$color","red"] }, { $not : "$color" }]},
                            then: "$$DESCEND",
                            else: "$$PRUNE"
                            }
                            }}]);


                            $redact "restricts the contents of the documents based on information stored in the documents themselves". So it will run only inside of the document. It basically scans your document top to the bottom, and checks if it matches with your if condition which is in $cond, if there is match it will either keep the content($$DESCEND) or remove($$PRUNE).



                            In the example above, first $match returns the whole shapes array, and $redact strips it down to the expected result.



                            Note that {$not:"$color"} is necessary, because it will scan the top document as well, and if $redact does not find a color field on the top level this will return false that might strip the whole document which we don't want.






                            share|improve this answer

















                            • 1




                              perfect answer. As you mentioned $unwind will consume lot of RAM. So this will be better when compared.
                              – manojpt
                              Apr 21 '15 at 11:21










                            • I have a doubt. In the example, "shapes" is an array. Will "$redact" scan all the objects in the "shapes" array ?? How this will be good with respect to performance??
                              – manojpt
                              Apr 23 '15 at 8:13












                            • not all of it, but the result of your first match. That is the reason why you put $match as your first aggregate stage
                              – anvarik
                              Apr 23 '15 at 16:36










                            • okkk.. if an index created on "color" field, even then it will scan all the objects in the "shapes" array??? Which could be the efficient way of matching multiple objects in an array???
                              – manojpt
                              Apr 24 '15 at 4:47






                            • 2




                              Brilliant! I do not understand how $eq works here. I left it off originally and this didn't work for me. Somehow, it looks in the array of shapes to find the match, but the query never specifies which array to look in. Like, if the documents had shapes and, for example, sizes; would $eq look in both arrays for matches? Is $redact just looking for anything within the document that matches the 'if' condition?
                              – Onosa
                              Dec 30 '15 at 14:46














                            27












                            27








                            27






                            Another interesing way is to use $redact, which is one of the new aggregation features of MongoDB 2.6. If you are using 2.6, you don't need an $unwind which might cause you performance problems if you have large arrays.



                            db.test.aggregate([
                            { $match: {
                            shapes: { $elemMatch: {color: "red"} }
                            }},
                            { $redact : {
                            $cond: {
                            if: { $or : [{ $eq: ["$color","red"] }, { $not : "$color" }]},
                            then: "$$DESCEND",
                            else: "$$PRUNE"
                            }
                            }}]);


                            $redact "restricts the contents of the documents based on information stored in the documents themselves". So it will run only inside of the document. It basically scans your document top to the bottom, and checks if it matches with your if condition which is in $cond, if there is match it will either keep the content($$DESCEND) or remove($$PRUNE).



                            In the example above, first $match returns the whole shapes array, and $redact strips it down to the expected result.



                            Note that {$not:"$color"} is necessary, because it will scan the top document as well, and if $redact does not find a color field on the top level this will return false that might strip the whole document which we don't want.






                            share|improve this answer












                            Another interesing way is to use $redact, which is one of the new aggregation features of MongoDB 2.6. If you are using 2.6, you don't need an $unwind which might cause you performance problems if you have large arrays.



                            db.test.aggregate([
                            { $match: {
                            shapes: { $elemMatch: {color: "red"} }
                            }},
                            { $redact : {
                            $cond: {
                            if: { $or : [{ $eq: ["$color","red"] }, { $not : "$color" }]},
                            then: "$$DESCEND",
                            else: "$$PRUNE"
                            }
                            }}]);


                            $redact "restricts the contents of the documents based on information stored in the documents themselves". So it will run only inside of the document. It basically scans your document top to the bottom, and checks if it matches with your if condition which is in $cond, if there is match it will either keep the content($$DESCEND) or remove($$PRUNE).



                            In the example above, first $match returns the whole shapes array, and $redact strips it down to the expected result.



                            Note that {$not:"$color"} is necessary, because it will scan the top document as well, and if $redact does not find a color field on the top level this will return false that might strip the whole document which we don't want.







                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered Jun 4 '14 at 8:31









                            anvarikanvarik

                            3,69532947




                            3,69532947








                            • 1




                              perfect answer. As you mentioned $unwind will consume lot of RAM. So this will be better when compared.
                              – manojpt
                              Apr 21 '15 at 11:21










                            • I have a doubt. In the example, "shapes" is an array. Will "$redact" scan all the objects in the "shapes" array ?? How this will be good with respect to performance??
                              – manojpt
                              Apr 23 '15 at 8:13












                            • not all of it, but the result of your first match. That is the reason why you put $match as your first aggregate stage
                              – anvarik
                              Apr 23 '15 at 16:36










                            • okkk.. if an index created on "color" field, even then it will scan all the objects in the "shapes" array??? Which could be the efficient way of matching multiple objects in an array???
                              – manojpt
                              Apr 24 '15 at 4:47






                            • 2




                              Brilliant! I do not understand how $eq works here. I left it off originally and this didn't work for me. Somehow, it looks in the array of shapes to find the match, but the query never specifies which array to look in. Like, if the documents had shapes and, for example, sizes; would $eq look in both arrays for matches? Is $redact just looking for anything within the document that matches the 'if' condition?
                              – Onosa
                              Dec 30 '15 at 14:46














                            • 1




                              perfect answer. As you mentioned $unwind will consume lot of RAM. So this will be better when compared.
                              – manojpt
                              Apr 21 '15 at 11:21










                            • I have a doubt. In the example, "shapes" is an array. Will "$redact" scan all the objects in the "shapes" array ?? How this will be good with respect to performance??
                              – manojpt
                              Apr 23 '15 at 8:13












                            • not all of it, but the result of your first match. That is the reason why you put $match as your first aggregate stage
                              – anvarik
                              Apr 23 '15 at 16:36










                            • okkk.. if an index created on "color" field, even then it will scan all the objects in the "shapes" array??? Which could be the efficient way of matching multiple objects in an array???
                              – manojpt
                              Apr 24 '15 at 4:47






                            • 2




                              Brilliant! I do not understand how $eq works here. I left it off originally and this didn't work for me. Somehow, it looks in the array of shapes to find the match, but the query never specifies which array to look in. Like, if the documents had shapes and, for example, sizes; would $eq look in both arrays for matches? Is $redact just looking for anything within the document that matches the 'if' condition?
                              – Onosa
                              Dec 30 '15 at 14:46








                            1




                            1




                            perfect answer. As you mentioned $unwind will consume lot of RAM. So this will be better when compared.
                            – manojpt
                            Apr 21 '15 at 11:21




                            perfect answer. As you mentioned $unwind will consume lot of RAM. So this will be better when compared.
                            – manojpt
                            Apr 21 '15 at 11:21












                            I have a doubt. In the example, "shapes" is an array. Will "$redact" scan all the objects in the "shapes" array ?? How this will be good with respect to performance??
                            – manojpt
                            Apr 23 '15 at 8:13






                            I have a doubt. In the example, "shapes" is an array. Will "$redact" scan all the objects in the "shapes" array ?? How this will be good with respect to performance??
                            – manojpt
                            Apr 23 '15 at 8:13














                            not all of it, but the result of your first match. That is the reason why you put $match as your first aggregate stage
                            – anvarik
                            Apr 23 '15 at 16:36




                            not all of it, but the result of your first match. That is the reason why you put $match as your first aggregate stage
                            – anvarik
                            Apr 23 '15 at 16:36












                            okkk.. if an index created on "color" field, even then it will scan all the objects in the "shapes" array??? Which could be the efficient way of matching multiple objects in an array???
                            – manojpt
                            Apr 24 '15 at 4:47




                            okkk.. if an index created on "color" field, even then it will scan all the objects in the "shapes" array??? Which could be the efficient way of matching multiple objects in an array???
                            – manojpt
                            Apr 24 '15 at 4:47




                            2




                            2




                            Brilliant! I do not understand how $eq works here. I left it off originally and this didn't work for me. Somehow, it looks in the array of shapes to find the match, but the query never specifies which array to look in. Like, if the documents had shapes and, for example, sizes; would $eq look in both arrays for matches? Is $redact just looking for anything within the document that matches the 'if' condition?
                            – Onosa
                            Dec 30 '15 at 14:46




                            Brilliant! I do not understand how $eq works here. I left it off originally and this didn't work for me. Somehow, it looks in the array of shapes to find the match, but the query never specifies which array to look in. Like, if the documents had shapes and, for example, sizes; would $eq look in both arrays for matches? Is $redact just looking for anything within the document that matches the 'if' condition?
                            – Onosa
                            Dec 30 '15 at 14:46











                            18














                            Better you can query in matching array element using $slice is it helpful to returning the significant object in an array.



                            db.test.find({"shapes.color" : "blue"}, {"shapes.$" : 1})


                            $slice is helpful when you know the index of the element, but sometimes you want
                            whichever array element matched your criteria. You can return the matching element
                            with the $ operator.






                            share|improve this answer




























                              18














                              Better you can query in matching array element using $slice is it helpful to returning the significant object in an array.



                              db.test.find({"shapes.color" : "blue"}, {"shapes.$" : 1})


                              $slice is helpful when you know the index of the element, but sometimes you want
                              whichever array element matched your criteria. You can return the matching element
                              with the $ operator.






                              share|improve this answer


























                                18












                                18








                                18






                                Better you can query in matching array element using $slice is it helpful to returning the significant object in an array.



                                db.test.find({"shapes.color" : "blue"}, {"shapes.$" : 1})


                                $slice is helpful when you know the index of the element, but sometimes you want
                                whichever array element matched your criteria. You can return the matching element
                                with the $ operator.






                                share|improve this answer














                                Better you can query in matching array element using $slice is it helpful to returning the significant object in an array.



                                db.test.find({"shapes.color" : "blue"}, {"shapes.$" : 1})


                                $slice is helpful when you know the index of the element, but sometimes you want
                                whichever array element matched your criteria. You can return the matching element
                                with the $ operator.







                                share|improve this answer














                                share|improve this answer



                                share|improve this answer








                                edited Sep 18 '14 at 9:14









                                Egor Neliuba

                                10.5k64164




                                10.5k64164










                                answered Sep 18 '14 at 8:35









                                NarendranNarendran

                                42246




                                42246























                                    11














                                    The syntax for find in mongodb is



                                        db.<collection name>.find(query, projection);


                                    and the second query that you have written, that is



                                        db.test.find(
                                    {shapes: {"$elemMatch": {color: "red"}}},
                                    {"shapes.color":1})


                                    in this you have used the $elemMatch operator in query part, whereas if you use this operator in the projection part then you will get the desired result. You can write down your query as



                                         db.users.find(
                                    {"shapes.color":"red"},
                                    {_id:0, shapes: {$elemMatch : {color: "red"}}})


                                    This will give you the desired result.






                                    share|improve this answer



















                                    • 1




                                      This works for me. However, It appears that "shapes.color":"red" in the query parameter (the first parameter of the find method) is not necessary. You can replace it with {} and get the same results.
                                      – Erik Olson
                                      May 9 '14 at 20:35






                                    • 2




                                      @ErikOlson Your suggestion is right in the above case, where we need to find all the document that with red color and to apply the projection on them only. But let's say if somebody requires to find out all the document that have color blue but it should return only those element of that shapes array that have color red. In this case the above query can be referenced by somebody else also..
                                      – Vicky
                                      May 11 '14 at 9:22










                                    • This seems to be the easiest, but I can't make it work it. It only returns the first matching subdocument.
                                      – newman
                                      Aug 29 '15 at 23:05
















                                    11














                                    The syntax for find in mongodb is



                                        db.<collection name>.find(query, projection);


                                    and the second query that you have written, that is



                                        db.test.find(
                                    {shapes: {"$elemMatch": {color: "red"}}},
                                    {"shapes.color":1})


                                    in this you have used the $elemMatch operator in query part, whereas if you use this operator in the projection part then you will get the desired result. You can write down your query as



                                         db.users.find(
                                    {"shapes.color":"red"},
                                    {_id:0, shapes: {$elemMatch : {color: "red"}}})


                                    This will give you the desired result.






                                    share|improve this answer



















                                    • 1




                                      This works for me. However, It appears that "shapes.color":"red" in the query parameter (the first parameter of the find method) is not necessary. You can replace it with {} and get the same results.
                                      – Erik Olson
                                      May 9 '14 at 20:35






                                    • 2




                                      @ErikOlson Your suggestion is right in the above case, where we need to find all the document that with red color and to apply the projection on them only. But let's say if somebody requires to find out all the document that have color blue but it should return only those element of that shapes array that have color red. In this case the above query can be referenced by somebody else also..
                                      – Vicky
                                      May 11 '14 at 9:22










                                    • This seems to be the easiest, but I can't make it work it. It only returns the first matching subdocument.
                                      – newman
                                      Aug 29 '15 at 23:05














                                    11












                                    11








                                    11






                                    The syntax for find in mongodb is



                                        db.<collection name>.find(query, projection);


                                    and the second query that you have written, that is



                                        db.test.find(
                                    {shapes: {"$elemMatch": {color: "red"}}},
                                    {"shapes.color":1})


                                    in this you have used the $elemMatch operator in query part, whereas if you use this operator in the projection part then you will get the desired result. You can write down your query as



                                         db.users.find(
                                    {"shapes.color":"red"},
                                    {_id:0, shapes: {$elemMatch : {color: "red"}}})


                                    This will give you the desired result.






                                    share|improve this answer














                                    The syntax for find in mongodb is



                                        db.<collection name>.find(query, projection);


                                    and the second query that you have written, that is



                                        db.test.find(
                                    {shapes: {"$elemMatch": {color: "red"}}},
                                    {"shapes.color":1})


                                    in this you have used the $elemMatch operator in query part, whereas if you use this operator in the projection part then you will get the desired result. You can write down your query as



                                         db.users.find(
                                    {"shapes.color":"red"},
                                    {_id:0, shapes: {$elemMatch : {color: "red"}}})


                                    This will give you the desired result.







                                    share|improve this answer














                                    share|improve this answer



                                    share|improve this answer








                                    edited Jan 31 '14 at 8:19









                                    Jinxcat

                                    4191316




                                    4191316










                                    answered Dec 22 '13 at 8:14









                                    VickyVicky

                                    447314




                                    447314








                                    • 1




                                      This works for me. However, It appears that "shapes.color":"red" in the query parameter (the first parameter of the find method) is not necessary. You can replace it with {} and get the same results.
                                      – Erik Olson
                                      May 9 '14 at 20:35






                                    • 2




                                      @ErikOlson Your suggestion is right in the above case, where we need to find all the document that with red color and to apply the projection on them only. But let's say if somebody requires to find out all the document that have color blue but it should return only those element of that shapes array that have color red. In this case the above query can be referenced by somebody else also..
                                      – Vicky
                                      May 11 '14 at 9:22










                                    • This seems to be the easiest, but I can't make it work it. It only returns the first matching subdocument.
                                      – newman
                                      Aug 29 '15 at 23:05














                                    • 1




                                      This works for me. However, It appears that "shapes.color":"red" in the query parameter (the first parameter of the find method) is not necessary. You can replace it with {} and get the same results.
                                      – Erik Olson
                                      May 9 '14 at 20:35






                                    • 2




                                      @ErikOlson Your suggestion is right in the above case, where we need to find all the document that with red color and to apply the projection on them only. But let's say if somebody requires to find out all the document that have color blue but it should return only those element of that shapes array that have color red. In this case the above query can be referenced by somebody else also..
                                      – Vicky
                                      May 11 '14 at 9:22










                                    • This seems to be the easiest, but I can't make it work it. It only returns the first matching subdocument.
                                      – newman
                                      Aug 29 '15 at 23:05








                                    1




                                    1




                                    This works for me. However, It appears that "shapes.color":"red" in the query parameter (the first parameter of the find method) is not necessary. You can replace it with {} and get the same results.
                                    – Erik Olson
                                    May 9 '14 at 20:35




                                    This works for me. However, It appears that "shapes.color":"red" in the query parameter (the first parameter of the find method) is not necessary. You can replace it with {} and get the same results.
                                    – Erik Olson
                                    May 9 '14 at 20:35




                                    2




                                    2




                                    @ErikOlson Your suggestion is right in the above case, where we need to find all the document that with red color and to apply the projection on them only. But let's say if somebody requires to find out all the document that have color blue but it should return only those element of that shapes array that have color red. In this case the above query can be referenced by somebody else also..
                                    – Vicky
                                    May 11 '14 at 9:22




                                    @ErikOlson Your suggestion is right in the above case, where we need to find all the document that with red color and to apply the projection on them only. But let's say if somebody requires to find out all the document that have color blue but it should return only those element of that shapes array that have color red. In this case the above query can be referenced by somebody else also..
                                    – Vicky
                                    May 11 '14 at 9:22












                                    This seems to be the easiest, but I can't make it work it. It only returns the first matching subdocument.
                                    – newman
                                    Aug 29 '15 at 23:05




                                    This seems to be the easiest, but I can't make it work it. It only returns the first matching subdocument.
                                    – newman
                                    Aug 29 '15 at 23:05











                                    11














                                     db.getCollection('aj').find({"shapes.color":"red"},{"shapes.$":1})


                                    OUTPUTS



                                    {

                                    "shapes" : [
                                    {
                                    "shape" : "circle",
                                    "color" : "red"
                                    }
                                    ]
                                    }





                                    share|improve this answer


























                                      11














                                       db.getCollection('aj').find({"shapes.color":"red"},{"shapes.$":1})


                                      OUTPUTS



                                      {

                                      "shapes" : [
                                      {
                                      "shape" : "circle",
                                      "color" : "red"
                                      }
                                      ]
                                      }





                                      share|improve this answer
























                                        11












                                        11








                                        11






                                         db.getCollection('aj').find({"shapes.color":"red"},{"shapes.$":1})


                                        OUTPUTS



                                        {

                                        "shapes" : [
                                        {
                                        "shape" : "circle",
                                        "color" : "red"
                                        }
                                        ]
                                        }





                                        share|improve this answer












                                         db.getCollection('aj').find({"shapes.color":"red"},{"shapes.$":1})


                                        OUTPUTS



                                        {

                                        "shapes" : [
                                        {
                                        "shape" : "circle",
                                        "color" : "red"
                                        }
                                        ]
                                        }






                                        share|improve this answer












                                        share|improve this answer



                                        share|improve this answer










                                        answered Dec 7 '16 at 6:25









                                        Viral PatelViral Patel

                                        54369




                                        54369























                                            7














                                            Thanks to JohnnyHK.



                                            Here I just want to add some more complex usage.



                                            // Document 
                                            {
                                            "_id" : 1
                                            "shapes" : [
                                            {"shape" : "square", "color" : "red"},
                                            {"shape" : "circle", "color" : "green"}
                                            ]
                                            }

                                            {
                                            "_id" : 2
                                            "shapes" : [
                                            {"shape" : "square", "color" : "red"},
                                            {"shape" : "circle", "color" : "green"}
                                            ]
                                            }


                                            // The Query
                                            db.contents.find({
                                            "_id" : ObjectId(1),
                                            "shapes.color":"red"
                                            },{
                                            "_id": 0,
                                            "shapes" :{
                                            "$elemMatch":{
                                            "color" : "red"
                                            }
                                            }
                                            })


                                            //And the Result

                                            {"shapes":[
                                            {
                                            "shape" : "square",
                                            "color" : "red"
                                            }
                                            ]}





                                            share|improve this answer




























                                              7














                                              Thanks to JohnnyHK.



                                              Here I just want to add some more complex usage.



                                              // Document 
                                              {
                                              "_id" : 1
                                              "shapes" : [
                                              {"shape" : "square", "color" : "red"},
                                              {"shape" : "circle", "color" : "green"}
                                              ]
                                              }

                                              {
                                              "_id" : 2
                                              "shapes" : [
                                              {"shape" : "square", "color" : "red"},
                                              {"shape" : "circle", "color" : "green"}
                                              ]
                                              }


                                              // The Query
                                              db.contents.find({
                                              "_id" : ObjectId(1),
                                              "shapes.color":"red"
                                              },{
                                              "_id": 0,
                                              "shapes" :{
                                              "$elemMatch":{
                                              "color" : "red"
                                              }
                                              }
                                              })


                                              //And the Result

                                              {"shapes":[
                                              {
                                              "shape" : "square",
                                              "color" : "red"
                                              }
                                              ]}





                                              share|improve this answer


























                                                7












                                                7








                                                7






                                                Thanks to JohnnyHK.



                                                Here I just want to add some more complex usage.



                                                // Document 
                                                {
                                                "_id" : 1
                                                "shapes" : [
                                                {"shape" : "square", "color" : "red"},
                                                {"shape" : "circle", "color" : "green"}
                                                ]
                                                }

                                                {
                                                "_id" : 2
                                                "shapes" : [
                                                {"shape" : "square", "color" : "red"},
                                                {"shape" : "circle", "color" : "green"}
                                                ]
                                                }


                                                // The Query
                                                db.contents.find({
                                                "_id" : ObjectId(1),
                                                "shapes.color":"red"
                                                },{
                                                "_id": 0,
                                                "shapes" :{
                                                "$elemMatch":{
                                                "color" : "red"
                                                }
                                                }
                                                })


                                                //And the Result

                                                {"shapes":[
                                                {
                                                "shape" : "square",
                                                "color" : "red"
                                                }
                                                ]}





                                                share|improve this answer














                                                Thanks to JohnnyHK.



                                                Here I just want to add some more complex usage.



                                                // Document 
                                                {
                                                "_id" : 1
                                                "shapes" : [
                                                {"shape" : "square", "color" : "red"},
                                                {"shape" : "circle", "color" : "green"}
                                                ]
                                                }

                                                {
                                                "_id" : 2
                                                "shapes" : [
                                                {"shape" : "square", "color" : "red"},
                                                {"shape" : "circle", "color" : "green"}
                                                ]
                                                }


                                                // The Query
                                                db.contents.find({
                                                "_id" : ObjectId(1),
                                                "shapes.color":"red"
                                                },{
                                                "_id": 0,
                                                "shapes" :{
                                                "$elemMatch":{
                                                "color" : "red"
                                                }
                                                }
                                                })


                                                //And the Result

                                                {"shapes":[
                                                {
                                                "shape" : "square",
                                                "color" : "red"
                                                }
                                                ]}






                                                share|improve this answer














                                                share|improve this answer



                                                share|improve this answer








                                                edited May 23 '17 at 11:54









                                                Community

                                                11




                                                11










                                                answered Mar 23 '14 at 7:05









                                                EddyEddy

                                                1,8952427




                                                1,8952427























                                                    5














                                                    You just need to run query



                                                    db.test.find(
                                                    {"shapes.color": "red"},
                                                    {shapes: {$elemMatch: {color: "red"}}});


                                                    output of this query is



                                                    {
                                                    "_id" : ObjectId("562e7c594c12942f08fe4192"),
                                                    "shapes" : [
                                                    {"shape" : "circle", "color" : "red"}
                                                    ]
                                                    }


                                                    as you expected it'll gives the exact field from array that matches color:'red'.






                                                    share|improve this answer




























                                                      5














                                                      You just need to run query



                                                      db.test.find(
                                                      {"shapes.color": "red"},
                                                      {shapes: {$elemMatch: {color: "red"}}});


                                                      output of this query is



                                                      {
                                                      "_id" : ObjectId("562e7c594c12942f08fe4192"),
                                                      "shapes" : [
                                                      {"shape" : "circle", "color" : "red"}
                                                      ]
                                                      }


                                                      as you expected it'll gives the exact field from array that matches color:'red'.






                                                      share|improve this answer


























                                                        5












                                                        5








                                                        5






                                                        You just need to run query



                                                        db.test.find(
                                                        {"shapes.color": "red"},
                                                        {shapes: {$elemMatch: {color: "red"}}});


                                                        output of this query is



                                                        {
                                                        "_id" : ObjectId("562e7c594c12942f08fe4192"),
                                                        "shapes" : [
                                                        {"shape" : "circle", "color" : "red"}
                                                        ]
                                                        }


                                                        as you expected it'll gives the exact field from array that matches color:'red'.






                                                        share|improve this answer














                                                        You just need to run query



                                                        db.test.find(
                                                        {"shapes.color": "red"},
                                                        {shapes: {$elemMatch: {color: "red"}}});


                                                        output of this query is



                                                        {
                                                        "_id" : ObjectId("562e7c594c12942f08fe4192"),
                                                        "shapes" : [
                                                        {"shape" : "circle", "color" : "red"}
                                                        ]
                                                        }


                                                        as you expected it'll gives the exact field from array that matches color:'red'.







                                                        share|improve this answer














                                                        share|improve this answer



                                                        share|improve this answer








                                                        edited Nov 10 '16 at 7:50









                                                        azhar

                                                        8341932




                                                        8341932










                                                        answered Sep 17 '16 at 17:22









                                                        Vaibhav PatilVaibhav Patil

                                                        567514




                                                        567514























                                                            2














                                                            along with $project it will be more appropriate other wise matching elements will be clubbed together with other elements in document.



                                                            db.test.aggregate(
                                                            { "$unwind" : "$shapes" },
                                                            { "$match" : {
                                                            "shapes.color": "red"
                                                            }},
                                                            {"$project":{
                                                            "_id":1,
                                                            "item":1
                                                            }}
                                                            )





                                                            share|improve this answer





















                                                            • can you pls describe that this accomplishes with an input and output set?
                                                              – Alexander Mills
                                                              Nov 24 '15 at 17:13
















                                                            2














                                                            along with $project it will be more appropriate other wise matching elements will be clubbed together with other elements in document.



                                                            db.test.aggregate(
                                                            { "$unwind" : "$shapes" },
                                                            { "$match" : {
                                                            "shapes.color": "red"
                                                            }},
                                                            {"$project":{
                                                            "_id":1,
                                                            "item":1
                                                            }}
                                                            )





                                                            share|improve this answer





















                                                            • can you pls describe that this accomplishes with an input and output set?
                                                              – Alexander Mills
                                                              Nov 24 '15 at 17:13














                                                            2












                                                            2








                                                            2






                                                            along with $project it will be more appropriate other wise matching elements will be clubbed together with other elements in document.



                                                            db.test.aggregate(
                                                            { "$unwind" : "$shapes" },
                                                            { "$match" : {
                                                            "shapes.color": "red"
                                                            }},
                                                            {"$project":{
                                                            "_id":1,
                                                            "item":1
                                                            }}
                                                            )





                                                            share|improve this answer












                                                            along with $project it will be more appropriate other wise matching elements will be clubbed together with other elements in document.



                                                            db.test.aggregate(
                                                            { "$unwind" : "$shapes" },
                                                            { "$match" : {
                                                            "shapes.color": "red"
                                                            }},
                                                            {"$project":{
                                                            "_id":1,
                                                            "item":1
                                                            }}
                                                            )






                                                            share|improve this answer












                                                            share|improve this answer



                                                            share|improve this answer










                                                            answered Feb 9 '13 at 15:45









                                                            shakthydossshakthydoss

                                                            1,34021630




                                                            1,34021630












                                                            • can you pls describe that this accomplishes with an input and output set?
                                                              – Alexander Mills
                                                              Nov 24 '15 at 17:13


















                                                            • can you pls describe that this accomplishes with an input and output set?
                                                              – Alexander Mills
                                                              Nov 24 '15 at 17:13
















                                                            can you pls describe that this accomplishes with an input and output set?
                                                            – Alexander Mills
                                                            Nov 24 '15 at 17:13




                                                            can you pls describe that this accomplishes with an input and output set?
                                                            – Alexander Mills
                                                            Nov 24 '15 at 17:13











                                                            0














                                                            db.test.find( {"shapes.color": "red"}, {_id: 0})





                                                            share|improve this answer



















                                                            • 1




                                                              Welcome to Stack Overflow! Thank you for the code snippet, which might provide some limited, immediate help. A proper explanation would greatly improve its long-term value by describing why this is a good solution to the problem, and would make it more useful to future readers with other similar questions. Please edit your answer to add some explanation, including the assumptions you've made.
                                                              – sepehr
                                                              Oct 25 '18 at 15:06
















                                                            0














                                                            db.test.find( {"shapes.color": "red"}, {_id: 0})





                                                            share|improve this answer



















                                                            • 1




                                                              Welcome to Stack Overflow! Thank you for the code snippet, which might provide some limited, immediate help. A proper explanation would greatly improve its long-term value by describing why this is a good solution to the problem, and would make it more useful to future readers with other similar questions. Please edit your answer to add some explanation, including the assumptions you've made.
                                                              – sepehr
                                                              Oct 25 '18 at 15:06














                                                            0












                                                            0








                                                            0






                                                            db.test.find( {"shapes.color": "red"}, {_id: 0})





                                                            share|improve this answer














                                                            db.test.find( {"shapes.color": "red"}, {_id: 0})






                                                            share|improve this answer














                                                            share|improve this answer



                                                            share|improve this answer








                                                            edited Oct 25 '18 at 8:04









                                                            Suraj Rao

                                                            22.7k75469




                                                            22.7k75469










                                                            answered Oct 25 '18 at 8:00









                                                            Poonam AgrawalPoonam Agrawal

                                                            92




                                                            92








                                                            • 1




                                                              Welcome to Stack Overflow! Thank you for the code snippet, which might provide some limited, immediate help. A proper explanation would greatly improve its long-term value by describing why this is a good solution to the problem, and would make it more useful to future readers with other similar questions. Please edit your answer to add some explanation, including the assumptions you've made.
                                                              – sepehr
                                                              Oct 25 '18 at 15:06














                                                            • 1




                                                              Welcome to Stack Overflow! Thank you for the code snippet, which might provide some limited, immediate help. A proper explanation would greatly improve its long-term value by describing why this is a good solution to the problem, and would make it more useful to future readers with other similar questions. Please edit your answer to add some explanation, including the assumptions you've made.
                                                              – sepehr
                                                              Oct 25 '18 at 15:06








                                                            1




                                                            1




                                                            Welcome to Stack Overflow! Thank you for the code snippet, which might provide some limited, immediate help. A proper explanation would greatly improve its long-term value by describing why this is a good solution to the problem, and would make it more useful to future readers with other similar questions. Please edit your answer to add some explanation, including the assumptions you've made.
                                                            – sepehr
                                                            Oct 25 '18 at 15:06




                                                            Welcome to Stack Overflow! Thank you for the code snippet, which might provide some limited, immediate help. A proper explanation would greatly improve its long-term value by describing why this is a good solution to the problem, and would make it more useful to future readers with other similar questions. Please edit your answer to add some explanation, including the assumptions you've made.
                                                            – sepehr
                                                            Oct 25 '18 at 15:06





                                                            protected by Samuel Liew Oct 5 '15 at 9:21



                                                            Thank you for your interest in this question.
                                                            Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).



                                                            Would you like to answer one of these unanswered questions instead?



                                                            Popular posts from this blog

                                                            Costa Masnaga

                                                            Fotorealismo

                                                            Sidney Franklin