Home > other >  MongoDB Aggregation - Show all sub documents with some information from parent document
MongoDB Aggregation - Show all sub documents with some information from parent document

Time:12-22

My invoices collection looks something like this:

[
  {
    inv_name: "Client 1",
    inv_date: 2022-12-20T05:09:09.803Z,
    inv_ready: false,
    inv_payments: [
      {
        id: "123",
        pay_amount: 32.45
      },
      {
        id: "456",
        pay_amount: 55.60
      }
    ]
  },
  {
    inv_name: "Client 2",
    inv_date: 2022-12-19T05:09:09.803Z,
    inv_ready: true,
    inv_payments: [
      {
        id: "459",
        pay_amount: 67.45
      },
      {
        id: "556",
        pay_amount: 30.60
      }
    ]
  }
]

I know how to create an array of just the sub docs using $project and $unwind. The goal is to just add some data from the parent document to each object like this.

[
  {
    "client": "Client 1",
    "pay_amount": 32.45,
    "pay_date": "123"
  },
  {
    "client": "Client 1",
    "pay_amount": 55.6,
    "pay_date": "456"
  },
  {
    "client": "Client 2",
    "pay_amount": 67.45,
    "pay_date": "459"
  },
  {
    "client": "Client 2",
    "pay_amount": 30.6,
    "pay_date": "556"
  }
]

Here is what I tried:

db.invoices.aggregate([
  {
    "$project": {
      _id: 0,
      "inv_payments": {
        $reduce: {
          input: "$inv_payments",
          initialValue: [],
          in: {
            $concatArrays: [
              [
                {
                  client: "$this.name",
                  pay_id: "$$this.id",
                  pay_amount: "$$this.pay_amount"
                }
              ],
              "$inv_payments"
            ]
          }
        }
      }
    }
  },
  {
    $unwind: "$inv_payments"
  },
  {
    $replaceRoot: {
      newRoot: "$inv_payments"
    }
  }
])

I think I am close. I am not sure where the bug is. Any ideas would be greatly appreciated!

CodePudding user response:

Besides the typo error mentioned in the comment, the way you used the $reduce operator is incorrect. You didn't work with the accumulator variable ($$value).

Rather than using $reduce, use the $map operator which is simpler in your scenario:

Solution 1: $map

{
  "$project": {
    _id: 0,
    "inv_payments": {
      $map: {
        input: "$inv_payments",
        in: {
          client: "$inv_name",
          pay_date: "$$this.id",
          pay_amount: "$$this.pay_amount"
        }
      }
    }
  }
}

Demo ($map) @ Mongo Playground


Solution 2: $reduce

For $reduce operator, your query should be:

{
  "$project": {
    _id: 0,
    "inv_payments": {
      $reduce: {
        input: "$inv_payments",
        initialValue: [],
        in: {
          $concatArrays: [
            [
              {
                client: "$inv_name",
                pay_date: "$$this.id",
                pay_amount: "$$this.pay_amount"
              }
            ],
            "$$value"
          ]
        }
      }
    }
  }
}

Demo ($reduce) @ Mongo Playground

  • Related