Home > Blockchain >  Mongoose findOneAndUpdate object in array
Mongoose findOneAndUpdate object in array

Time:09-07

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.

CodePudding user response:

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.

  • Related