Calculations in $push or $push as pipeLineStage

The Goal: $push an object into an array based on data retrieved from the other array elements.

Idea 1: Model.updateOne({}, {$push: : { “field”: {$max: {.field}} }})
==> This does not work because mongo thinks that $max is an object property and not a calculation initiator.

Idea 2: Use aggregate, add Field with the calculation (coz there it is accepted as a calculation) and $push that to the array, or $addToSet,
==> This does not work because $push and $addToSet are not pipeline stages and thus can’t be called independently

I also tried to do it with $unwind and stuff but that also does not work

So if somebody has a clue how to activate calculations in $push like it is in $addField stage or some other idea, please help

Hello @Maximilian_N_A, welcome to the forum!

I think you should go with the Idea 2, as the Updates With Aggregation Pipeline allows to use other document fields (or their derived values) to be set to some other fields.

Instead, you should use the Aggregation Operators - specifically, the Array Expression Operators, since you want to work with an array field and its elements. The operator I have on my mind is the $concatArrays. This allows adding new elements to an array field.

I hope you find this useful :slight_smile:

1 Like

I will look into that but I am sure, that will make it even more complicated.

At this point I thought I will just do it with the $function accumulator to bypass all the jibjab and do it that way. Now I surprisingly found out, that despite the mongo Compass passing the aggregation, actually using the aggregation from my nestjs application does not work.
This seems rather counterintuitive.

let insert = await this.testSchema.insertMany([{
      ProjId: 12,
      ArtifactAttributes: [
        {
          _t: "ArtifactAttributes",
          AttrId: 1,
          AttributeName: "Description",
          AttributeValue: "Test Description"
        },
        {
          _t: "ArtifactAttributes",
          AttrId: 2,
          AttributeName: "Details",
          AttributeValue: "Test Details"
        }
      ]
    }])

    let toBeInserted = {
      "_t": "ArtifactAttributes",
      "AttrId": 0,
      "AttributeName": "Owner",
      "AttributeValue": "Test Owner"
    }
    await this.testSchema.aggregate([{
      $set: {
        "ArtifactAttributes": {
          "$function": {
            body: function (obj, inserter) {
              obj.sort((a, b) => b.AttrId - a.AttrId)
              inserter["AttrId"] = obj[0].AttrId + 1
              obj.push(inserter)
              return obj
            },
            args: ["$ArtifactAttributes", {
              "_t": "ArtifactAttributes",
              "AttrId": 1,
              "AttributeName": "Owner",
              "AttributeValue": "Test Owner"
            }],
            lang: "js"
          }
        }
      }
    }])

This is exactly the aggregation from mongoCompass:

But calling that function RETURNS the updated document, but does not apply it in the database…

{
    "_id": {
        "$oid": "61b7819a86c901a8cc159b0a"
    },
    "ArtifactAttributes": [{
        "_t": "ArtifactAttributes",
        "AttrId": 1,
        "AttributeName": "Description",
        "AttributeValue": "Test Description"
    }, {
        "_t": "ArtifactAttributes",
        "AttrId": 2,
        "AttributeName": "Details",
        "AttributeValue": "Test Details"
    }],
    "ProjId": 12,
    "__v": 0
}

But console logging the request gives me the new object:

{
    "_id": "61b780cebc97c5e07b523b44",
    "ArtifactAttributes": [
      {
        "_t": "ArtifactAttributes",
        "AttrId": 2,
        "AttributeName": "Details",
        "AttributeValue": "Test Details"
      },
      {
        "_t": "ArtifactAttributes",
        "AttrId": 1,
        "AttributeName": "Description",
        "AttributeValue": "Test Description"
      },
      {
        "_t": "ArtifactAttributes",
        "AttrId": 3,
        "AttributeName": "Owner",
        "AttributeValue": "Test Owner"
      }
    ],
    "ProjId": 12,
    "__v": 0
  }

Actually that concating worked, thank you very much

Other quick question:
Why the heck does unset say it is not properly formatted:
image

That is an aggregation query you had tried. The Aggregation Update is like the following update statement, which changes the data in the database:

db.collection.updateOne(
  { _id: "some value" },
  [
      { $set: { .... } }
  ]
)

Also refer:

1 Like

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.