0

I would like to insert or update an object in an array, but I dont know how to do it.

My Schema:

const TelemetrySchema = new mongoose.Schema({
  Client: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Client',
  },
  MQTT_FIELD: [
    {
      _id: false,
      Index:
      {
        type: Number,
        required: true,
        unique: true,
      },
      Name: {
        type: String,
        trim: true,
        required: true,
        unique: true,
      },
    },
  ],
});

I would like to update MQTT_FIELD in my TelemetrySchema:

First, search for Client in Telemetry, insert in MQTT_FIELD, if not exist:

Index = 1, Name = 'K1'

Second, serach for Client in Telemetry, update if not exist

Index = 1, Name = 'K-1'

What did I so far:

    const telemetry = await Telemetry.findOneAndUpdate(
      {
        MQTT_CLIENT: req.body.Client,
        'MQTT_FIELD.Index': { $ne: req.body.Field.Index },
      },
      {
        $addToSet: {
          MQTT_FIELD: {
            Index: req.body.Field.Index,
            Name: req.body.Field.Name,
          },
        },
      },
      {
        upsert: true,
        new: true,
        omitUndefined: true,
      },
    ).exec();

Inserting in an empty Array MQTT_FIELD works well, but updating is my problem.

I am getting the following error:

duplicate key error collection: mycollection.telemetries index: MQTT_FIELD.Index_1 dup key: { MQTT_FIELD.Index: 1 }

And here is my request body:

{
  "Client": "stackoverflow",
  "Field":
        {
            "Index": 1,
            "Name": "S1"
        }
}

Thanks in advance.

1 Answer 1

1

You will have to use the aggregation-pipeline form of update in MongoDb. Something like this:

db.collection.update({
  "client": "stackoverflow"
},
[
  {
    "$set": {
      "MQTT_FIELD": {
        "$cond": {
          "if": {
            "$eq": [
              {
                "$size": {
                  "$filter": {
                    "input": "$MQTT_FIELD",
                    "as": "elem",
                    "cond": {
                      "$eq": [
                        "$$elem.index",
                        2 <--- Substitute the index from your request body here
                      ]
                    }
                  }
                }
              },
              0
            ]
          },
          "then": {
            "$concatArrays": [
              "$MQTT_FIELD",
              [
                {
                  name: "S1", <--- Substitute the name from your request body here
                  index: 1 <--- Substitute the index from your request body here
                }
              ]
            ]
          },
          "else": {
            "$map": {
              "input": "$MQTT_FIELD",
              "as": "elem",
              "in": {
                "$setField": {
                  "field": "name",
                  "input": "$$elem",
                  "value": "S1" <-- substitute the name from your request body here.
                }
              }
            }
          }
        }
      }
    }
  }
])

Note you can use either update OR findOneAndUpdate, any function will work. Here's the playground link.

Sign up to request clarification or add additional context in comments.

2 Comments

as far as I understood, I need here is a sequence of update operations, that each "try" to perform their expected action. This can only be done with multiple statements: mongodb $addToSet to a non-array field when update on upsert
That is one way of doing that, for versions less than 4.2. For versions 4.2 or above the above way should work

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.