0

I am using nodejs npm mongodb

mongodb version: mongodb@3.1.9 nodejs version: v10.11.0

Here is the document layout:

{
    "_id": {
        "$oid": "5c1bc140a3902a10542df7a6"
    },
    "email": "radoslav.k.marrinov@gmail.com",
    "username": "rikotech",
    "deviceId": "FA661234A511",
    "password": "12345",
    "devices": [
        {
            "_id": {
                "$oid": "5c1bb980fb6fc00eee83b4d9"
            },
            "id": "FA661234A511",
            "class": "11",
            "name": "someName",
            "displayName": "disName",
            "endpoints": [
                {
                    "class": "binarySwitch",
                    "name": "bs1",
                    "displayName": "sw1DisplName"
                },
                {
                    "class": "binarySwitch",
                    "name": "bs2",
                    "displayName": "sw2DisplName"
                }
            ]
        }
    ]
}

I want to change the value of devices[0].endpoints[0].displayName: "newName"

I am able to locate the document having the device.id and endpoint.displayName

This query finds the document: { devices: { $elemMatch: { id: "FA661234A511" } } }

I know I should be using update method but I can not figure out the how to select the field to update?

I have to find the first occurrence of device with "id": "FA661234A511" and then the first occurrence of endpoint with "displayName": "sw1DisplName"

id is unique in the scope of devices and displayName is unique in the scope of endpoints

I tried whit this:

update({
    devices: {
      $elemMatch: {
        id: "FA661234A511",
        endpoints: { $elemMatch: { displayName: "sw1DisplName" } }
      }
    }
  }, {
    "devices.$.endpoints.$.displayName": "diplayRiko"
  })

Doesn't work :(.

I get exception:

MongoError: Too many positional (i.e. '$') elements found in path 'devices.$.endpoints.$.displayName'

Hairi
  • 3,318
  • 2
  • 29
  • 68
  • what is your mongo server version ? – s7vr Jan 15 '19 at 13:48
  • @Veeram Changed the post. See at the beginning – Hairi Jan 15 '19 at 13:54
  • Not mongodb driver version. I'm asking mongo server version. You can run db.version() on mongo shell to see the version. In any case any server version below 3.6 nested arrays update is not supported. You can see the example [here](https://stackoverflow.com/questions/51912697/mongoose-how-to-update-array-element-which-contains-in-another-array/51913067#51913067) – s7vr Jan 15 '19 at 14:06
  • VERSION: 3.6.8 (MMAPv1) I am using free version in mlab.com – Hairi Jan 15 '19 at 14:15
  • Tried thisone: `collection.updateOne({ "devices.id": "FA661234A511" }, { $set: { "devices.$[devEl].endpoints.$[epEl].displayName": "EEADSASDASD" } }, { arrayFilters: [ { devEl: { id: "FA661234A511" } }, { epEl: { displayName: "sw1DisplName" } } ] })` Didnt work – Hairi Jan 15 '19 at 14:18
  • 1
    Try `collection.updateOne({ "devices.id": "FA661234A511" }, { $set: { "devices.$[devEl].endpoints.$[epEl].displayName": "EEADSASDASD" } }, { arrayFilters: [ { "devEl.id": "FA661234A511" } , { "epEl.displayName": "sw1DisplName" } ] })` – s7vr Jan 15 '19 at 14:19
  • At first glance it works. Why isn't mine not working? As far as I see the only difference is in the syntax: ` {epEl: { displayName: "sw1DisplName" }}` vs `{ "epEl.displayName": "sw1DisplName" }`. I looked in the docs – Hairi Jan 15 '19 at 14:25
  • 1
    yes you have to use dotation to refer an array element / embedded docuement. – s7vr Jan 15 '19 at 14:26
  • @Veeram Ok thanks you can scratch some answer so I can accept it :) – Hairi Jan 15 '19 at 14:28

1 Answers1

1

Have you tried the $set operator?

The $set operator replaces the value of a field with the specified value.

{ $set: { <field1>: <value1>, ... } }

I suppose this will work:

db.yourcollection.update({ devices[0].id: "FA661234A511" }, { $set: "endpoints.0.displayName": "newName" })

Mongodb docs: https://docs.mongodb.com/manual/reference/operator/update/set/

Gabriel Silva
  • 69
  • 1
  • 9
  • I could id my query selector matches the exact nested array element. Now it selects only on level `devices` – Hairi Jan 14 '19 at 17:53
  • What you have changed in the query? – Gabriel Silva Jan 14 '19 at 18:00
  • Why would you use the '$' in "devices.$.endpoints.$.displayName"? Have you tried my suggestion? – Gabriel Silva Jan 14 '19 at 19:45
  • You say I can use `"endpoints.0.displayName"`, but what if the endpoint with `"displayName": "sw1DisplName"` is the second element of the array? – Hairi Jan 15 '19 at 13:06
  • I mean I could not know the exact index/position of the array element that matches the criteria 1) device with `id: "FA661234A511"` 2) endpoints with `displayName: "sw1DisplName" ` – Hairi Jan 15 '19 at 13:42