2

I try to update field with value in euro but something's going wrong.

db.orders.update({
    "_id": ObjectId("56892f6065380a21019dc810")
}, {
    $set: {
        "wartoscEUR": {
            $multiply: ["wartoscPLN", 4]
        }
    }
})

I got an error:

The dollar ($) prefixed field '$multiply' in 'wartoscEUR.$multiply' is not valid for storage.

WartoscPLN and WartoscEUR are number fields, and i'd like to calculate wartoscEUR by multiplying wartoscPLN by 4.

Sorry, maybe this is really easy but I'm just getting starting in nosql.

Matheus Cuba
  • 2,068
  • 1
  • 20
  • 31
mauro
  • 21
  • 1
  • 3
  • 1
    Looks like a dupe of http://stackoverflow.com/questions/3974985/update-mongodb-field-using-value-of-another-field. In short, you can't reference the value of another field in an update. – JohnnyHK Jan 03 '16 at 16:12

2 Answers2

3

The $multiply-operator is only used in aggregation. The operator you are looking for is $mul and it has a different syntax:

db.orders.update(
    {"_id" : ObjectId("56892f6065380a21019dc810")},
    { $mul: { wartoscPLN: 4 }
);

It is not necessary to combine it with $set, as it implies that semantic implicitly.

Philipp
  • 67,764
  • 9
  • 118
  • 153
1

The $multiply operator can only be used in the aggregation framework, not in an update operation. You could use the aggregation framework in your case to create a new result set that has the new field wartoscEUR created with the $project pipeline.

From the result set you can then loop through it (using the forEach() method of the cursor returned from the .aggregate() method), update your collection with the new value but you cannot access a value of a document directly in an update statement hence the Bulk API update operation come in handy here:

The Bulk update will at least allow many operations to be sent in a single request with a singular response.

The above operation can be depicted with this implementation:

var bulk = db.orders.initializeOrderedBulkOp(),
    counter = 0;

db.orders.aggregate([
    {
        "$project": {                
            "wartoscEUR": { "$multiply": ["$wartoscPLN", 4] }
        }
    }
]).forEach(function (doc) {
    bulk.find({ "_id": doc._id }).updateOne({
        "$set": { "wartoscEUR": doc.wartoscEUR }
    });

    counter++;

    if (counter % 1000 == 0) {
        bulk.execute();
        bulk = db.orders.initializeOrderedBulkOp();
    }
});

if (counter % 1000 != 0) {
    bulk.execute();
}
chridam
  • 100,957
  • 23
  • 236
  • 235
  • If you are loading the documents into your application anyway, you can just as well use a normal `find` instead of an aggregation and do the multiplication in javascript... or just use [$mul](https://docs.mongodb.org/manual/reference/operator/update/mul/#up._S_mul) – Philipp Jan 03 '16 at 15:54
  • chridam: Ok thx, i will try, but i have to say i thing it will be easy like in sql... Philipp: i try mul but then i got value in field wartoscPLN not in wartoscEUR, i dont have access into an aplication – mauro Jan 03 '16 at 16:02
  • Thanks, your answer is super useful! – Serhii Smirnov Jan 25 '22 at 17:55