0

I have a collection of documents like this:

{
  "_id" : ObjectId("532d4e7d569c9e4574d5156e"),
  "title" : "Book Title"
  "author" : "Book Author",
  "owner" : "532d4e7c569c9e4574d51568",
  "pages" : [
    {
      "texts" : [
        {
          "_id" : ObjectId("532d4e7d569c9e4574d51572"),
          "paragraphs" : [ ],
          "format" : [ ],
          "position" : {
            "y" : 0,
            "x" : 0
          }
        }
      ],
      "images" : [
        {
          "_id" : ObjectId("532d4e7f569c9e4574d51573"),
          "position" : {
            "y" : 0,
            "x" : 0
          }
        }
      ],
    },
    {
      "_id" : ObjectId("532d4e7d569c9e4574d51571"),
      "videos" : [ ],
      "audios" : [ ],
      "images" : [ ],
      "texts" : [ ],
      "animations" : [ ]
    }
  ]
}

and I want to get the only text subdocument with _id:

db.projects.find({'pages.texts._id': ObjectId("532d4e7d569c9e4574d51572")}, {'pages.$.texts.$': 1}).pretty()

but it's not works.

I want to get only this part of document:

{
  "_id" : ObjectId("532d4e7d569c9e4574d51572"),
  "paragraphs" : [ ],
  "format" : [ ],
  "position" : {
    "y" : 0,
    "x" : 0
  }
}
Anton Shuvalov
  • 3,560
  • 3
  • 16
  • 20

1 Answers1

1

From the documentation for the positional $ operator:

The positional $ operator limits the contents of the field that is included in the query results to contain the first matching element. To specify an array element to update, see the positional $ operator for updates.

You have two arrays. First is pages. Second is texts.

The "position" is only matched on the first array and not again. You can do this with .aggregate() :

Projects.aggregate([
       // Match documents
       { "$match": {
           "pages.texts._id": ObjectId("532d4e7d569c9e4574d51572")
       }},

       // Unwind the pages array
       { "$unwind": "$pages" },

       // Unwind the "texts" array
       { "$unwind": "$pages.texts" },

       // Filter array
       { "$match": {
           "pages.texts._id": ObjectId("532d4e7d569c9e4574d51572")
       }},

       // Re-form
       { "$group": {
           "_id": "$_id",
           "texts": { "$push": "$pages.texts"  }
       }}
    ],
    function(err, res) {
       // do things with res or err here
})

And the mongoose documentation.

More on aggregation operators.

More reading here

Community
  • 1
  • 1
Neil Lunn
  • 148,042
  • 36
  • 346
  • 317
  • is it ok: `"texts": { "$push": { "$pages.texts" } }`? – Anton Shuvalov Mar 22 '14 at 10:01
  • @AntonShuvalov Read [`$unwind`](http://docs.mongodb.org/manual/reference/operator/aggregation/unwind/) – Neil Lunn Mar 22 '14 at 10:03
  • @AntonShuvalov This is [aggregation](http://docs.mongodb.org/manual/reference/method/db.collection.aggregate/) and not **JavaScript**. Follow the "link". The "pipeline" is formatted as JSON. Same as `.find()` – Neil Lunn Mar 22 '14 at 10:10
  • I think, it's mistape: `"$push": _{_ "$pages.texts" _}_`. Without this braces all works perfect, but with it I get `syntax error`. – Anton Shuvalov Mar 22 '14 at 10:31
  • Awesome) In mongodb console all works correct, but how I can do this with mongoose? [This](https://gist.github.com/shuvalov-anton/9705337) doesn't works for me. https://gist.github.com/shuvalov-anton/9705337 – Anton Shuvalov Mar 22 '14 at 11:07
  • @AntonShuvalov And the mongoose way. Assuming `Projects` as the model. In the edit. – Neil Lunn Mar 22 '14 at 11:33
  • I found the reason of the problem with mongoose. `mongoose.Schema.ObjectId(req.params.textID);` return undefined, and when I use just string with `_id` it doesn't finds anything. – Anton Shuvalov Mar 22 '14 at 11:49
  • Fixed. All's right with `mongoose.Types.ObjectId`. Thank you so much! – Anton Shuvalov Mar 22 '14 at 12:21