1

I have a collection 'users' with an array property called compass, which is a list of document objects. Below is one of the users in the collection:

{
  "_id": {
    "$oid": "64c4ef6615fc23530f9f2a29"
  },
  "username": "jay",
  "compass": [
    {
      "point": "64ce3416f695e4ddd587e982",
      "disposition": true,
      "_id": {
        "$oid": "64ceaa650b583901b5744d6b"
      }
    },
    {
      "point": "64ce343bf695e4ddd587e983",
      "disposition": true,
      "_id": {
        "$oid": "64cf622faba9c3c1dd607994"
      }
    }
  ]
}

I'm writing a function to search the compass array looking for a match in the point property. If it does not exist, it creates a new array element, and if it does exist it updates the disposition property to a new value. I'm developing in the context of a MERN stack and using the mongoose library. In my current function, below, UserModel.js is imported and contains my UserModel schema:

export const setPoint = async(req, res) => {
    try {
        const user = await UserModel.findById(req.body.userId);
        const disposition = req.body.disposition;
        const pointId = req.body.pointId;
        var index = undefined; 
        for (var i = 0; i < user._doc.compass.length; i++) {
            if (user._doc.compass[i].point == pointId) {
                index = i;
            }
        }
        if (index !== undefined) {
            await user.updateOne( 
                {"compass.point": pointId }, 
                { $set: {"compass.$.disposition": disposition } }, 
                false, 
                false );    
        } else {
            const newObj = {point: pointId, disposition: disposition }
            await user.updateOne( {$push: { compass: newObj } } );
        }
        res.status(200).json("Point set.");
    } catch (error) {
        res.status(500).json(error);
    }
}

When I test using a pointId that doesn't exist in the compass array, it successfully pushes the new element onto the array, and so I know the request is reaching the server and being parsed correctly. However, when I test using a point that exists in the array and attempt to change the disposition property of an existing object, it fails with status 500, with a server response of:

{
  "index": 0,
  "code": 28
}

From the documentation it's clear that I want to use the $ positional operator, which I have seen successfully implemented here and here. As far as I can tell, I'm using it just as in the docs with the exception that I'm trying to update a document using a schema.

Troubleshooting:

When I use the updateOne() method in mongosh, the disposition is successfully changed:

db.users.updateOne(
   { "compass.point": "64ce343bf695e4ddd587e983" },
   { $set: { "compass.$.disposition" : false } }
)

which leads me to believe that it's a problem with either my query document or my update document.

I've confirmed that the pointId is the same as the point value I'm targeting:

console.log(pointId); // 64ce343bf695e4ddd587e983
console.log(user._doc.compass[1].point) // 64ce343bf695e4ddd587e983
console.log(user._doc.compass[1].point === pointId); // true

When I remove the query document and the "upsert" and "multi" parameters, and specify the index in the update document, the correct element is targeted and updated:

await user.updateOne( { $set: {"compass.1.disposition": disposition } } );

My questions:

  1. What is the server response telling me? I have not been able to find "code": 28 in the docs, or anywhere else.

  2. What part of my user.updateOne syntax is incorrect?

    (curiosities:)

  3. If I went with the clunkier approach of using the value of the index variable generated in the for loop to specify the compass element directly, what syntax would I use (instead of 'compass.$.disposition')?

  4. Pushing a new element onto the array in the else statement generates a new document, but both my schema and the object that I'm inserting only specify an object with point and disposition properties. Why is MongoDB creating a new document with an _id field?

0 Answers0