Home > Software engineering >  Mongodb: How to pass another stage inside $group?
Mongodb: How to pass another stage inside $group?

Time:02-25


Sample Data


Expected Output:

[
  {
    "_id": "healty",
    "doc_count": 2,
    "ingredients": {
      "Leaves": {
        "1.2g": 1,
        "1.5g": 1
      },
      "Spinach": {
        "12g": 1,
        "18g": 1
      }
    }
  },
  {
    "_id": "junk",
    "doc_count": 3,
    "ingredients": {
      "cheese": {
        "100g": 1,
        "120g": 2
      },
      "meat": {
        "50g": 1,
        "60g": 1,
        "70g": 1
      }
    }
  }
]

Aggregation Below: Playground1

db.collection.aggregate([
  {
    $group: {       
      "_id": "$type",  // grouping the document by "type" field
      "ingredients": {
        $push: "$$ROOT"  //want to run Playground2 aggrgtion in each of it
      },
      "doc_count": {
        $sum: 1        // total count
      }
    }
  }
])


After that,

I've also figured out an Another Step to convert the ingredients array after it: Playground2

But, this aggregation is for All the documents. I want to make Playground2 aggregation work for the ingredients field only in each group Object.

It's similar to combining Playground1 & Playground2. How do I do this?

CodePudding user response:

db.collection.aggregate([
  {
    "$set": {
      "ingredients": {
        "$objectToArray": "$ingredients"
      }
    }
  },
  {
    "$unwind": "$ingredients"
  },
  {
    "$group": {
      "_id": {
        type: "$type",
        ingredient: "$ingredients"
      },
      "count": {
        "$sum": 1
      },
      "doc_count": {
        "$addToSet": "$item"
      }
    }
  },
  {
    "$group": {
      "_id": {
        type: "$_id.type",
        ingredient: "$_id.ingredient.k"
      },
      "docs": {
        "$push": {
          k: "$_id.ingredient.v",
          v: "$count"
        }
      },
      "doc_count": {
        "$push": "$doc_count"
      }
    }
  },
  {
    "$group": {
      "_id": "$_id.type",
      "ingredients": {
        "$push": {
          k: "$_id.ingredient",
          v: {
            "$arrayToObject": "$docs"
          }
        }
      },
      "doc_count": {
        "$push": {
          $reduce: {
            input: "$doc_count",
            initialValue: [],
            in: {
              $concatArrays: [
                "$$value",
                "$$this"
              ]
            }
          }
        }
      }
    }
  },
  {
    "$set": {
      "ingredients": {
        "$arrayToObject": "$ingredients"
      },
      doc_count: {
        "$size": {
          "$setUnion": {
            $reduce: {
              input: "$doc_count",
              initialValue: [],
              in: {
                $concatArrays: [
                  "$$value",
                  "$$this"
                ]
              }
            }
          }
        }
      }
    }
  }
])

mongoplayground

  • Related