0

I have a MongoDB instance configured in MongoDB Atlas. The instance contains two collections:

  • Col_A
  • Col_B

When I update any object in Col_B, I have a MongoDB trigger which then uses the information in the Col_B changeEvent and updates part of what is a very large schema in the Col_A object matching the same ID.

exports = function(changeEvent) {
  
  //Access the _id of the changed document:
  const docId = changeEvent.documentKey._id;
  const mongodb = context.services.get("MongoDBInst");
  
  const collection = mongodb.db("MongoDB").collection("Col_A");
  collection.updateOne(
    { _id: docId },
    { 
      $set: {
        "Field1.Subfield1.Val1": changeEvent.fullDocument.value1,
        "Field1.Subfield1.Val2": changeEvent.fullDocument.value2
      }
    }
  );
  console.log("Data updated for: " + docId);

This works for most objects that already have Field1 and Subfield1 set, however, some of the objects in my database have Field1 or Subfield one set to null which results in the following error:

uncaught promise rejection: write exception: write errors: [Cannot create field 'Val2' in element {Subfield1: null}]

I looked up the error and tried to implement the below:

exports = function(changeEvent) {
  
  //Access the _id of the changed document:
  const docId = changeEvent.documentKey._id;
  const mongodb = context.services.get("MongoDBInst");
  
  const collection = mongodb.db("MongoDB").collection("Col_A");
  collection.updateOne(
    { _id: docId },
    { 
      $set: {
        "Field1": {
          "Subfield1": {
            "Val1": changeEvent.fullDocument.value1,
            "Val2": changeEvent.fullDocument.value2
          }
        }
      }
    }
  );
  console.log("Data updated for: " + docId);

The problem with this, is that Field1 doesn't only contain Subfield1, it contains a number of Subfields and this essentially erases the rest of them.

Any ideas how to use the original dot notation and perhaps create the object prior to assigning the values? I'm new to MongoDB shell so hoping it's something quite simple that I'm missing.

TheFlanman91
  • 141
  • 1
  • 2
  • 11

1 Answers1

0

You can try using pipelined form of update like this:

  collection.updateOne(
    { _id: docId },
     [
      {
        "$set": {
          "Field1": {
            "$cond": {
              "if": {
                "$ne": [
                  "$Field1",
                  null
                ]
              },
              "then": {
                "$mergeObjects": [
                  "$Field1",
                    {
                    "Subfield1": {
                      "Val1": changeEvent.fullDocument.value1,
                      "Val2": changeEvent.fullDocument.value2
                    }
                  }
                ]
              },
              "else": {
                "Subfield1": {
                  "Val1": changeEvent.fullDocument.value1,
                  "Val2": changeEvent.fullDocument.value2
                }
              }
            }
          }
        }
      }
    ]
   );

Here, we set the Field1 conditionally, if it's non-null, then we merge the current Field1 with the new SubField1, otherwise, we just create a new object with just SubField1.

Charchit Kapoor
  • 8,934
  • 2
  • 8
  • 24