Muirik
Muirik

Reputation: 6289

Using $addFields as part of an update function in MongoDB

I am trying to figure out how to use the $addFields operation within a function I'm using to update a document. The logic to generate this field is simple enough, I just pull out the last object in an array, like so:

  {
    $addFields: { activeWorkflow: { $arrayElemAt: ["$workflow", -1.0] } }
  }

Now I need to figure out how to get this aggregation into my update function, the relevant code of which looks like this:

updatedDoc = await request.findOneAndUpdate(
  StaffMember,
  {
    _id: request.parameters.id
  },
  req,
  {
    new: true
  }
);

What I tried doing was this:

updatedDoc = await request.findOneAndUpdate(
  StaffMember,
  {
    _id: request.parameters.id
  },
  req,
  {
    new: true
  }
);

await request.aggregate(updatedDoc, [
  {
    $addFields: { activeWorkflow: { $arrayElemAt: ["$workflow", -1.0] } }
  }
]);

... but this gives me an error:

TypeError: mongooseModelObject.aggregate is not a function

Would I use the $addFields operator with $set, like so?

updatedDoc = await request.findOneAndUpdate(
      StaffMember,
      {
        _id: request.parameters.id
      },
      {
        $set: {
          req,
          $addFields: { activeWorkflow: { $arrayElemAt: ["$workflow", -1.0] } }
        }
      },
      {
        new: true
      }
    );

How does one run an aggregation as part of a function like this? A simple example would help me understand how this needs to be done -- if indeed it can be done.

Of course, there are other ways to do this, but I'd like to take advantage of a mongo-specific way to handle this, using a mongo operation like $addFields. What would this look like?

By the way, the wrapper function I'm using with aggregate looks like this:

  async aggregate(mongooseModelObject, aggregateObject = {}) {
    try {
      return await mongooseModelObject.aggregate(aggregateObject).exec();
    } catch (err) {
      this.sendError(err);
    }
  }

Upvotes: 4

Views: 6748

Answers (3)

DoanTuyet
DoanTuyet

Reputation: 1

db.col.aggregate won't change data in collection but db.col.insertMany will

db.temperatures.updateMany({}, [{$addFields: {"fields-name": "value"}}])

Upvotes: 0

Haseeb Anwar
Haseeb Anwar

Reputation: 2918

Starting from MongoDB 4.2, findAndUpdateOne, updateOne, updateMany can accept an aggregation pipeline for the update.

const updatedDocument = await DocumentModel.updateOne({ _id: id }, [
  {
     $set: {
       items: items,
     }
  },
  {
     $addFields: { totalItems: { $sum: '$items.quantity' } },
  }
 ],
 { new: true } // to return updated document
);

Upvotes: 2

mickl
mickl

Reputation: 49985

Basically you can't use aggregate as part of an update. The only way to update the data using $addFields is to use $out like this:

db.col.aggregate([
    {  $addFields: { activeWorkflow: { $arrayElemAt: ["$workflow", -1.0] } } },
    {  $out: "col" }
])

but this will unfortunately add activeWorkflow for all the documents in col.

For regular .update() you can't refer to another field so the only way to do that for single doc is use to findOne() to get that document, then add new field in your application logic and then use update() or save() to store that updated document (old question here).

Upvotes: 4

Related Questions