How to modify fields in specific sub-documents in an array?

43 views Asked by At

I have a collection where each document has an array of sub-documents, containing several fields. I need to update specific sub-documents based on their fields, but every attempt I've done so far changes the field in all of the arrayed sub-documents

Here is some sample data:

{ 
    '_id' : ObjectId('0001'),
    'Region' : 'Northern',
    "Items" : [
        {
            "ItemId" : NumberInt(25), 
            "Name" : "Widget", 
            "ProductType" : "15", 
            "ItemIdLegacy" : "ca-000037"
        }, 
        {
            "ItemId" : NumberInt(30), 
            "Name" : "Gizmo", 
            "ProductType" : "15", 
            "ItemIdLegacy" : "ca-000038"
        },
        {
            "ItemId" : NumberInt(35), 
            "Name" : "Thingy", 
            "ProductType" : "15", 
            "ItemIdLegacy" : "ca-000039"
        }
    ] 
}

When I try to use update() with the following query, it updates the ProductType on all array items, not just the one I'm trying to change.

To clarify, I want to change the array item with ItemIdLegacy: "ca-000038" to have ProductType: 20. All other Array items should remain unchanged. Query that I have tried:

db.Collection.update({"Items.ItemIdLegacy" : "ca-000038"},[{$set: { "Items.ProductType" : "20"} }],{multi: false});

This is the desired output:

{ 
    '_id' : ObjectId('0001'),
    'Region' : 'Northern',
    "Items" : [
        {
            "ItemId" : NumberInt(25), 
            "Name" : "Widget", 
            "ProductType" : "15", 
            "ItemIdLegacy" : "ca-000037"
        }, 
        {
            "ItemId" : NumberInt(30), 
            "Name" : "Gizmo", 
            "ProductType" : "20", 
            "ItemIdLegacy" : "ca-000038"
        },
        {
            "ItemId" : NumberInt(35), 
            "Name" : "Thingy", 
            "ProductType" : "15", 
            "ItemIdLegacy" : "ca-000039"
        }
    ] 
}

But this is the actual output of running that query:

{ 
    '_id' : ObjectId('0001'),
    'Region' : 'Northern',
    "Items" : [
        {
            "ItemId" : NumberInt(25), 
            "Name" : "Widget", 
            "ProductType" : "20", 
            "ItemIdLegacy" : "ca-000037"
        }, 
        {
            "ItemId" : NumberInt(30), 
            "Name" : "Gizmo", 
            "ProductType" : "20", 
            "ItemIdLegacy" : "ca-000038"
        },
        {
            "ItemId" : NumberInt(35), 
            "Name" : "Thingy", 
            "ProductType" : "20", 
            "ItemIdLegacy" : "ca-000039"
        }
    ] 
}

I feel like I'm missing something simple...

EDIT: I have q uery that will allow me to update a single matching element in the array, but I have thousands that would need to be done so one offs don't necessarily work (sure I could parse them all out and spam them to the shell, but I want something more elegant)

Single Element Update:

db.Collection.updateOne({"Items.ItemIdLegacy" : "ca-000038"},{ $set: { "Items.$.ProductType" : "20" } } );
1

There are 1 answers

6
wak786 On

Try this :-

db.collection.update({
  "Items.ItemIdLegacy": "ca-000038"
},
{
  $set: {
    "Items.$.ProductType": 20
  }
},
{
  multi: true
})

Here is Working Example