Search code examples
mongodbmongodb-shell

How to convert a sting field to an ObjectId inside of an array of of objects via MongoDb Shell?


So my MongoDb doc looks like this:

{
    "_id" : ObjectId("5f1842d238ec58056d94bbb3"),
    "itemsPurchased" : [ 
        {
            "_id" : "5e7365360665d10011756af2",
            "created" : "2020-03-19T12:27:34.108Z",
            "productLine" : "5ce8ec9df5cc72002fee0d4e",
            "price" : 1.9,
            "tax" : 7,
            "ean" : "42272120",
            "expirationDate" : "2020-06-17T12:27:34.103Z",
            "kiosk" : "5c17a3d963ca649138ec522c",
            "loadCell" : "1"
        }, 
        {
            "_id" : "5e7365360665d10011756af3",
            "created" : "2020-03-19T12:27:34.108Z",
            "productLine" : "5ce8ec9df5cc72002fee0d4e",
            "price" : 1.9,
            "tax" : 7,
            "ean" : "42272120",
            "expirationDate" : "2020-06-17T12:27:34.103Z",
            "kiosk" : "5c17a3d963ca649138ec522c",
            "loadCell" : "1"
        }
    ],
    "paymentMethod" : [],
    "type" : "purchase",
    "total" : NumberDecimal("3.8"),
    "session" : ObjectId("5f1842bf1f2028e369d945f0"),
    "orgId" : ObjectId("5cddce9a51cbb2002d636741"),
    "created" : ISODate("2020-07-22T13:44:50.973Z"),
    "updated" : ISODate("2020-07-22T13:44:50.973Z"),
    "__v" : 0
}

The problem is that inside the itemsPurchased[] (due to a logical err) there are ids of type string. Here for example "_id" : "5e7365360665d10011756af2" and "productLine" : "5ce8ec9df5cc72002fee0d4e". How do I go through all documents that have an object in the itemsPurchased[] that has strings instead of ObjectIds and convert them to be of type ObjectId. I tried to use $convert and $toObjectId toghether with $map but can't seem to get it right.

db.transactions.aggregate([
  { "$match": { "itemsPurchased._id": {$type: "string"}}},
  { "$set": "itemsPurchased1": {
      "$map": {
        "input": "$itemsPurchased",
        "in": {
          "$toObjectId": [
            "$$this",
            {
              "productLine": {
                "$toObjectId": "$$this.productLine"
              }
            }
          ]
        }
      }
    }
  }

Can't get the map part right


Solution

  • You have used correctly $toObjectId, You just need to change $mergeObjects instead of $toObjectId, when you merge with $$this inside $map,

      {
        "$set": {
          "itemsPurchased1": {
            "$map": {
              "input": "$itemsPurchased",
              "in": {
                "$mergeObjects": ["$$this", { "productLine": { "$toObjectId": "$$this.productLine" } }]
              }
            }
          }
        }
      }
    

    Playground


    updateMany

    db.transactions.updateMany({}, 
    [
      {
        "$set": {
          "itemsPurchased": {
            "$map": {
              "input": "$itemsPurchased",
              "in": {
                "$mergeObjects": ["$$this", { "productLine": { "$toObjectId": "$$this.productLine" } }]
              }
            }
          }
        }
      }
    ])