2

I have the following array of collection of books. I'm trying to project a single property of an element in an array.

My query is projecting the text property in comments array for book of year 2012 for author A1.

Example books array:

[
    {
        book_id: "1",
        title:'B1',
        year: 2012,
        comments: [
            {
                author: "A1",
                text: "C1"
            }
        ]
    },
    {
        book_id: "2",
        title:'B2',
        year: 2012,
        comments: [
            {
                author: "A2",
                text: "C2.0"
            },
            {
                author: "A1",
                text: "C2.1"
            },
            {
                author: "A1",
                text: "C2.2"
            },

        ]
    },
    {
        book_id: "3",
        title:'B3',
        year: 2013,
        comments: [
            {
                author: "A1",
                text: "C3"
            }
        ]
    },
]

expected result


[
    "C1",
    "C2.1",
    "C2.2"
]

I tried the following:


// query using find

db.books.find(
{year:2012, comments: {$elemMatch : {author:"A1" } } },{_id:0,'comments.text':1}
)

// results
/* 1 */
{
    "comments" : [ 
        {
            "text" : "C1"
        }
    ]
}

/* 2 */
{
    "comments" : [ 
        {
            "text" : "C2.0"
        }, 
        {
            "text" : "C2.1"
        }, 
        {
            "text" : "C2.2"
        }
    ]
}


// query using aggregation


db.books.aggregate(
[
    {$match: {year:2012}},
    {
        $project:{
            comments: {
                $filter:{
                    input: "$comments",
                    as:'comment',
                    cond: {$eq:['$$comment.author','A1']}
                }
            }

        }
     }
])

// results in

/* 1 */
{
    "_id" : ObjectId("5d3446f9d9eac0ed968aad4b"),
    "comments" : [ 
        {
            "author" : "A1",
            "text" : "C1"
        }
    ]
}

/* 2 */
{
    "_id" : ObjectId("5d3446f9d9eac0ed968aad4c"),
    "comments" : [ 
        {
            "author" : "A1",
            "text" : "C2.1"
        }, 
        {
            "author" : "A1",
            "text" : "C2.2"
        }
    ]
}



2
  • Ideally you'd show us some of the existing code? Commented Jul 21, 2019 at 10:56
  • @Zlatko I added some of the queries i tried Commented Jul 21, 2019 at 11:22

1 Answer 1

4

You can use below aggregation

db.collection.aggregate([
  { "$match": { "year": 2012, "comments": { "$elemMatch": { "author": "A1" }}}},
  { "$unwind": "$comments" },
  { "$match": { "year": 2012, "comments.author": "A1" }},
  { "$group": {
    "_id": null,
    "data": { "$push": "$comments.text" }
  }}
])

Output

[
  {
    "_id": null,
    "data": [
      "C1",
      "C2.1",
      "C2.2"
    ]
  }
]

You cannot return simple array string with mongodb because it only returns the BSON document rather than just array of elements.

Sign up to request clarification or add additional context in comments.

2 Comments

thank you, but whats the purpose of the multiple $match, i removed the first match and got the same result. but when i delete the second $match keeping the first one ($elemMatch) the array adds the author A2 of comment C2.0. any idea why { "$match": { "year": 2012, "comments.author": "A1" }} workes over the one with $elemMatch ?
@AliKleit First $match is to filter out the documents which do not have the "comments.author" == A1, then $unwind deconstruct the comments array into multiple documents and last need to use $match again to again filter out the documents which do not have "comments.author" == "A1". You can remove one by one stages from result and can check the behaviour of various stages. mongoplayground.net/p/hJ_Ee8jPjAh

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.