Darkbound
Darkbound

Reputation: 3434

Delete all documents from a collection based on a condition and create missing ones

Now this is something that I already have managed to implement, I am just wondering if there is an easier/better way to do it as I am just starting to work with Mongoose and MongoDB.

Lets say that I have a couple of documents within a collection that have Name fields (I hope I got the terminology right), like this: [{Name: "Name1"}, {Name: "Name3"}], lets call it NamesConfiguration.

Now I also have a configuration array config with names: ["Name1", "Name2"].

My objective is to remove all names from NamesConfiguration that do not exist in the config array, and then add all names from the config array that do not exist in the NamesConfiguration, so my final collection should be [{Name: "Name1"}, {Name: "Name2"}].

try {
  const config = ["Name1", "Name2"];
  const NamesConfiguration = await UIConfiguration.find(); // getting all available nameconfigs from the db

  NamesConfiguration.forEach(async (nameConfig) => {
    if (!config.includes(nameConfig.Name)) {  // loop through and delete the ones that are not within the array
      console.log("deleting" + nameConfig.Name);
      await UIConfiguration.findOneAndDelete({ Name: nameConfig.Name });
    }
  });

  // loop through the array and see if the names are present
  config.forEach(async (configName) => {
    let found = NamesConfiguration.find((nameConfig) => nameConfig.Name === configName);

    // create new nameconfig if not found
    if (!found) {
      console.log("Creating" + configName);
      let NameConfigToAdd = new UIConfiguration({
        Name: configName
      });
      await NameConfigToAdd.save();
    }
  });
} catch (e) {
  console.log(e);
}

I just want to know if there is a better, "more proper" way of doing that operation. In my case even if this can potentially impact performance it will nto be an issue at all, since I will never have more than 10-20 entries.

Solved it by following Yousaf's answer:

  const availableConfigs = (await UIConfiguration.find()).map(
    (availableConfig) => {
      return availableConfig.Name;
    }
  );
  const configNamesToAdd = robotsNames
    .filter((robotName) => !availableConfigs.includes(robotName))
    .map((configName) => {
      return {
        Name: configName
      };
    });

  const deleteCondition = {
    Name: { $not: { $in: robotsNames } },
  };

  await UIConfiguration.deleteMany(deleteCondition);
  await UIConfiguration.insertMany(configNamesToAdd);

Upvotes: 1

Views: 1017

Answers (1)

Yousaf
Yousaf

Reputation: 29314

You can do it in following steps:

  1. Delete all the documents in the collection whose Name field's value is present in the config array.

    To delete any document whose Name field's value is not in the config array, write a delete query using $in and $not operators.

    UIConfiguration.deleteMany({ Name: { $not: { $in: ["Name1", "Name2"] } } });
    
  2. Fetch all the documents whose Name field's value exists in the config array. You can do this using $in operator

    UIConfiguration.find({ Name: { $in: ["Name1", "Name2"] } });
    
  3. Iterate over the returned array of documents and filter out those name strings in config array that do not match any document's Name field value.

  4. Finally, insert all the names in the filtered array in the collection using .insertMany method

    UIConfiguration.insertMany([/* filtered name objects */]);  
    

For further details on methods and operators used above, see:

Upvotes: 2

Related Questions