SpringerJerry
SpringerJerry

Reputation: 308

How to calculate a field in mongodb

Hello i am trying to make a caculate field in mongoDB, however i get this error: MongoError: The dollar ($) prefixed field '$add' in '$add' is not valid for storage.

This is the code:

router.post('/char1btn', ensureAuthenticated, function(req, res) {
    const {
        MongoClient
    } = require("mongodb");
    //Replace the uri string with your MongoDB deployment's connection string.
    const uri =
        'mongodb+srv://test:[email protected]/Databasetest?retryWrites=true&w=majority';
    const client = new MongoClient(uri);
    async function run() {
        try {
            await client.connect();
            const database = client.db("Databasetest");
            const collection = database.collection("users");
            //create a filter for charactername to update
            const filter = {
                characterimg: ""
            };
            // this option instructs the method to create a document if no documents match the filter
            const options = {
                upsert: false
            };
            const updateDoc = {
                $set: {
                    health: 150,
                    attack: 3,
                    defence: 3,
                    endurance: 10,
                    characterimg: "https://i.ibb.co/MPg2SMp/Apocaliptic1.png",
                },
                $set: {
                    $add: ["$power", "$attack", "$defence", {
                        $devide: ["$endurance", 3]
                    }]
                }
            }
            const result = await collection.updateOne(filter, updateDoc, options);
            console.log(
                `${result.matchedCount} document(s) matched the filter, updated ${result.modifiedCount} document(s)`,
            );
        } finally {
            res.redirect('/main');
            await client.close();
        }
    }
    run().catch(console.dir);
})

Does anyone know how to fix this?

Upvotes: 0

Views: 120

Answers (2)

Dheemanth Bhat
Dheemanth Bhat

Reputation: 4452

Update based on comment by @WernfriedDomscheit

if you are using MongoDB version > 4.2, then you can use pipeline inside update So the update query like below:

db.users.updateOne({},
  [
    {
      $set: {
        attack: 1,
        defence: 2,
        endurance: 3
      }
    },
    {
      $set: {
        power: {
          "$add": ["$attack", "$defence", { $divide: ["$endurance", 3] }]
        }
      }
    }
  ],
  { upsert: true }
);

will have the output:

{
    "_id" : ObjectId("603124a22391a75d9a2ddec0"),
    "attack" : 1,
    "defence" : 2,
    "endurance" : 3,
    "power" : 4
}

So in your case:

const updateDoc = [
  {
    $set: {
      health: 150,
      attack: 3,
      defence: 3,
      endurance: 10,
      characterimg: "https://i.ibb.co/MPg2SMp/Apocaliptic1.png",
    }
  },
  {
    $set: {      
      power: {
        $add: ["$attack", "$defence", { $divide: ["$endurance", 3] }]
      }
    }
  }
];

Upvotes: 1

Wernfried Domscheit
Wernfried Domscheit

Reputation: 59456

Try this one:

const updateDoc = [
   {
      $set: {
         health: 150,
         attack: 3,
         defence: 3,
         endurance: 10,
         characterimg: "https://i.ibb.co/MPg2SMp/Apocaliptic1.png",
      }
   },
   {
      $set: {
         result: { $sum: ["$power", "$attack", "$defence", { $divide: ["$endurance", 3] }] }
      }
   }
];
const result = await collection.updateOne(filter, updateDoc, options);

You need two $set stages. Otherwise $sum: [...] (or $add) will use old values or fail if fields did not exist before. Also be aware that updateDoc need to be an array, see updateOne()

Upvotes: 2

Related Questions