Home > OS >  Push an object to a nested array within a document but use a value from a field in the root document
Push an object to a nested array within a document but use a value from a field in the root document

Time:01-14

I've been scratching my head with this problem. I've attempted to search for a solution but I didn't find anything relating to my specific use case.

Would anyone be able to help me out?

Say I have a collection of "discount" documents, and importantly they have an "amount" field to say how much the discount is worth. Whenever a discount is redeemed I currently want to track what the worth was at the time of the redemption.

To do this I've been attempting to use the following code:

await datastore.collection('discounts').updateOne(
  {
    $expr: { $gt: [ '$maxUses', '$uses' ] },
    ...criteria
  },
  {
    $set: {
      uses: 1
    },
    $push: {
      redemptions: {
        name: concatNames(user),
        email: user.email,
        amount: '$amount', // <-- use amount from root document
        when: new Date()
      }
    }
  }
)

Unfortunately $amount does not pull the value from the root document, instead it just becomes "$amount" as a string. I've also attempted to convert this update to use a pipeline but $push is not a valid pipeline stage.

Here's a quick Mongo playground link.

Thanks in advance.

CodePudding user response:

In order to refer to another fields value, you'll need to use the aggregation pipeline form of update. However, '$push' is an update operator, not an aggregation operator.

$concatArrays gets most of the way there like {$set: {redepmtions: {$concatArrays: [ "$redemptions", [{amount: "$amount"}]}}

That will throw an error if $redemptions doesn't already exist, so use $cond to subsitute an empty array in that case:

.updateOne( 
  { ...criteria },
  [{$set: {
    redemptions: {$concatArrays: [
        {$cond: [{$eq: ["array", {$type: "$redemptions"}]}, "$redemptions", []]},
        [{amount: "$amount"}]
    ]}
  }}]
)

Playground

  • Related