Home > Net >  mongo aggregate - show all sub documents with some information from parent doc
mongo aggregate - show all sub documents with some information from parent doc

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_paymenents: [
   {
    id: '459',
    pay_amount: 67.45
   },
   {
    id: '556',
    pay_amount: 30.60
   }
  ]
 }]

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

[
  {
   id: '123',
   pay_amount: 32.45,
   inv_name: 'Client 1'
  },
  {
   id: '456',
   pay_amount: 55.60
   inv_name: 'Client 1'
  },
  {
   id: '459',
   pay_amount: 67.45
   inv_name: 'Client 2'
  },
  {
   id: '556',
   pay_amount: 30.60
   inv_name: 'Client 2'
  }]

Here is what I tried:

    {"$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