1
{
_id: ObjectId("5dbdacc28cffef0b94580dbd"),
 "comments" : [
     {
      "_id" : ObjectId("5dbdacc78cffef0b94580dbf"),
      "replies" : [
                   {
                     "_id" : ObjectId("5dbdacd78cffef0b94580dc0")          
                   },
                 ]
     },
  ]
}

How to count the number of element in comments and sum with number of relies

My approach is do 2 query like this:

1. total elements of replies

db.posts.aggregate([
{$match: {_id:ObjectId("5dbdacc28cffef0b94580dbd")}},

{ $unwind: "$comments",},

{$project:{total:{$size:"$comments.replies"} , _id: 0} }

])

2. count total elements of comments

db.posts.aggregate([
{$match: {_id:ObjectId("5dbdacc28cffef0b94580dbd")}},
{$project:{total:{$size:"$comments.replies"} , _id: 0} }

])

Then sum up both, do we have any better solution to write the query like return the sum of of total element comments + replies

Neil Lunn
  • 148,042
  • 36
  • 346
  • 317
tree em
  • 20,379
  • 30
  • 92
  • 130
  • 2
    Changed your question title to better reflect what you are asking. Your original question title choice was a little to close to a long standing existing question and answer. – Neil Lunn Nov 03 '19 at 10:04

3 Answers3

1

You can use $reduce and $concatArrays to "merge" an inner "array of arrays" into a single list and measure the $size of that. Then simply $add the two results together:

db.posts.aggregate([
  { "$match": { _id:ObjectId("5dbdacc28cffef0b94580dbd") } },
  { "$addFields": {
    "totalBoth": {
      "$add": [
        { "$size": "$comments" },
        { "$size": {
          "$reduce": {
            "input": "$comments.replies",
            "initialValue": [],
            "in": {
              "$concatArrays": [ "$$value", "$$this" ] 
            }
          }
        }}
      ]
    }
  }}
])

Noting that an "array of arrays" is the effect of an expression like $comments.replies, so hence the operation to make these into a single array where you can measure all elements.

Neil Lunn
  • 148,042
  • 36
  • 346
  • 317
0

Try using the $unwind to flatten the list you get from the $project before using $count.

Danny Varod
  • 17,324
  • 5
  • 69
  • 111
0

This is another way of getting the result.

Input documents:

{ "_id" : 1, "array1" : [ { "array2" : [ { id: "This is a test!"}, { id: "test1" } ] }, { "array2" : [ { id: "This is 2222!"}, { id: "test 222" }, { id: "222222" } ] } ] }
{ "_id" : 2, "array1" : [ { "array2" : [ { id: "aaaa" }, { id: "bbbb" } ] } ] }


The query:

db.arrsizes2.aggregate( [
  { $facet: {
     array1Sizes: [
          { $project: { array1Size: { $size: "$array1" } } }
     ],
     array2Sizes: [
          { $unwind: "$array1" },
          { $project: { array2Size: { $size: "$array1.array2" } } },
     ],
  } },
  { $project: { result: { $concatArrays: [ "$array1Sizes", "$array2Sizes" ] } } },
  { $unwind: "$result" },
  { $group: { _id: "$result._id", total1: { $sum: "$result.array1Size" }, total2: { $sum: "$result.array2Size" } } },
  { $addFields: { total: { $add: [ "$total1", "$total2" ] } } },
] )


The output:

{ "_id" : 2, "total1" : 1, "total2" : 2, "total" : 3 }
{ "_id" : 1, "total1" : 2, "total2" : 5, "total" : 7 }
prasad_
  • 12,755
  • 2
  • 24
  • 36