MongoDB - UpdateMany or Bulk.find.upsert for Upserting an Array of Objects

Viewed 443

I have an application that exports data from a Google Sheet to Mongo via a Mongo Realm HTTP Third Party Service; I'm not sure the Realm aspect is particularly relevant here but I may be wrong.

The export from Google Sheets sends an array of objects to Mongo ( example below), I want to update the documents where card_ids match, otherwise I want to create new documents. Initially I thought the way to do this would be via updatemany() but the examples where $set is used seem to have static values e.g.:

db.restaurant.updateMany(
      { violations: { $gt: 4 } },
      { $set: { "Review" : true } }
   );

I will know the name of the property, but not the value, and of course the value will be different in each of the objects/documents in the array I pass.

Looking at a similar question on SO (MongoDB updateMany, dynamic filter field) I can see the Bulk API is suggested and Bulk.find(<query>).upsert().update(<update>); seems like what I would want, but again I'm not sure how to use $set with dynamic values.

I'd be very grateful for any advice on the best way to achieve this.

Example Array send from Google Sheets to Mongo:

[
 { user: 'asdascom',
    userName: 'asdascom',
    year: 2019,
    player: 'terin test',
    manufacturer: 'Panini',
    brand: 'Natiosures',
    series: 'Rookigraphs',
    grader: 'PSA',
    graded_id: 0,
    career_stage: 'Rookard',
    team: 'Washington Football Team',
    card_number: 1,
    print_run: 99,
    number: 98,
    image_path: 'kjhkj',
    forTrade: 'No',
    status: 'Own',
    purchase_date: Tue Feb 02 2021 00:00:00 GMT+0000 (Greenwich Mean Time),
    card_id: 'cardid-1612814958860' },
  { user: 'jisdsdom',
    userName: 'jisdsdom',
    year: 2014,
    player: 'Terry Test2',
    manufacturer: 'Panini',
    brand: 'Flass',
    series: 'All Pro Ink',
    grader: 'PSA',
    graded_id: 23397853,
    career_stage: 'Roord',
    team: 'Washington Football Team',
    card_number: 1,
    print_run: 3,
    number: 2,
    image_path: 'kbkb',
    forTrade: 'No',
    status: 'Own',
    purchase_date: Fri Feb 05 2021 00:00:00 GMT+0000 (Greenwich Mean Time),
    card_id: 'cardid-1612815099960' } 
]
1 Answers

OK, I think I have worked out the answer to this, please see below - hope this is useful to someone, below I'm showing the full Realm function code:

const collection = context.services.get("mongodb-atlas").db("yourdb").collection("your collection");
const query = EJSON.parse(payload.body.text())
//console.log("payload.query "+ JSON.stringify(query));

return collection.bulkWrite(
  query.map(c => { 
    return { updateOne:
      {
        filter: { card_id: c.card_id },
        update: {$set: c},
        upsert : true
      }
    }
  }
  ),
  { ordered : false }
);
}
Related