📝 Josh's Notes

Seeding a MongoDB Collection Idempotently

MongoDB by default does not have a way to deduplicate entries. Two entries with identical fields can be created and MongoDB will create a unique ObjectId for them

To solve this, you can use MongoDB’s concept of upsert – essentially “update it, or create it if it doesn’t exist”

Here’s an example using mongoose. I’ve defined a schema for a collection called rbacGroups that looks like this:

 1const rbacGroupsSchema = new Schema({
 2  rbacGroupName: {
 3    type: String,
 4    required: true,
 5  },
 6  members: {
 7    type: Schema.Types.ObjectId,
 8    ref: 'users'
 9  },
10  createdAt: {
11    type: Date,
12    required: true,
13    immutable: true,
14    default: () => Date.now()
15  },
16}, { strict: "throw" })

Then, in a script for seeding the database with example/test data, use the following:

 1const seedRbacGroups = () => {
 2  for (i = 0; i < groupNames.length; i++){
 3    let rbacGroupName = groupNames[i]
 4    rbacGroupsModel.updateOne(
 5      { rbacGroupName: rbacGroupName }, // Query to search by
 6      {
 7        $set: {
 8          rbacGroupName: rbacGroupName
 9        }
10      }, // Updates to make to the document
11      { upsert: true} // Tell MongoDB to create the document if it doesn't exist
12    )
13    .then(msg => msg.upsertedId ? console.log(`New RBAC Group with name ${rbacGroupName} created. ${msg.upsertedId}`) : console.log(`Group with name ${rbacGroupName} already exists. Skipping...`))
14    .catch(err => console.error(err.message))
15  }
16}

I’m using the updateOne method from Mongoose, which is taking three parameters:

  1. The query to search by. In this case, we’re searching by the rbacGroupName
  2. The updates to make. This will either update the document matching the query, or create a document with these properties if nothing matches the query
  3. Options. In this case, we’re passing { upsert: true }

#mongodb #javascript #databases #programming