17

I'm using MongoDB's aggregation pipeline, to get my documents in the form that I want. As the last step of aggregation, I use $project to put the documents into their final form.

But I'm having trouble projecting and array of sub-documents. Here is what I currently get from aggrgation:

{
  "_id": "581c8c3df1325f68ffd23386",
  "count": 14,
  "authors": [
    {
      "author": {
        "author": "57f246b9e01e6c6f08e1d99a",
        "post": "581c8c3df1325f68ffd23386"
      },
      "count": 13
    },
    {
      "author": {
        "author": "5824382511f16d0f3fd5aaf2",
        "post": "581c8c3df1325f68ffd23386"
      },
      "count": 1
    }
  ]
}

I want to $project the authors array so that the return would be this:

{
  "_id": "581c8c3df1325f68ffd23386",
  "count": 14,
  "authors": [
    {
      "_id": "57f246b9e01e6c6f08e1d99a",
      "count": 13
    },
    {
      "_id": "5824382511f16d0f3fd5aaf2",
      "count": 1
    }
  ]
}

How would I go about achieving that?

1
  • 1
    Would be kind enough to edit your question to include the aggregation pipeline and some sample documents for testing? Commented Nov 11, 2016 at 10:15

3 Answers 3

17

I have been having the same problem and just now found a simple and elegant solution that has not been mentioned anywhere, so i thought I'd share it here:

You can iterate the array using $map and project each author. With the given structure, the aggregation should look somewhat like this

db.collectionName.aggregate([
  $project: {
    _id: 1,
    count:1,
    authors: {
      $map: {
        input: "$authors",
        as: "author",
        in: {
          id: "$$author.author.author",
          count: $$author.author.count
        }
      }
    } 
  }
])

Hope this helps anyone who is looking, like me :)

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

2 Comments

I had the same problem and your solution worked just great!!!
This is better solution, less stages, easier to understand in complex query
16

You can unwind the array and wind it u again after projecting. Something like this:

db.collectionName.aggregate([
{$unwind:'$authors'},
{$project:{_id:1,count:1,'author.id':'$authors.author.author','author.count':'$authors.count'}},
{$group:{_id:{_id:'$_id',count:'$count'},author:{$push:{id:'$author.id',count:'$author.count'}}}},
{$project:{_id:0,_id:'$_id._id',count:'$_id.count',author:1}}
])

the output for above will be:

{ 
    "_id" : "581c8c3df1325f68ffd23386", 
    "author" : [
        {
            "id" : "57f246b9e01e6c6f08e1d99a", 
            "count" : 13.0
        }, 
        {
            "id" : "5824382511f16d0f3fd5aaf2", 
            "count" : 1.0
        }
    ], 
    "count" : 14.0
}

1 Comment

is there a solution without $unwind?
4

Question:

"customFields" : [
    {
        "index" : "1",
        "value" : "true",
        "label" : "isOffline",
        "dataType" : "check_box",
        "placeholder" : "cf_isoffline",
        "valueFormatted" : "true"
    },

    {
        "index" : "2",
        "value" : "false",
        "label" : "tenure_extended",
        "dataType" : "check_box",
        "placeholder" : "cf_tenure_extended",
        "valueFormatted" : "false"
    }
],

Answer:

db.subscription.aggregate([
  {$match:{"autoCollect" : false,"remainingBillingCycles" : -1,"customFields.value":"false", "customFields.label" : "isOffline"}},
  {$project: {first: { $arrayElemAt: [ "$customFields", 1 ] }}}
])

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.