Mongoose $addToSet for array if item is unique

Viewed 175

Currently, my code just adds any new flagDtos with $addToSet regardless if item.name is unique or not unique, but I want to change this so that:

  • if item.nameis unique , Add the new flagDtos object
  • else update the flagDto if it matches a item.name.

How can I make the $addToSet based off a condition?

  async addFlagsToFeature(_id: number, flagDtos: FlagDto[]): Promise<FeatureResponse> {
    const filter: FilterQuery<FeatureDocument> = { _id };
    let success;
    var flagIds = [];

    return this.featureModel
      .findOneAndUpdate({ filter, $addToSet: { flags: flagDtos } })
      .then((doc) => {
        const featureDto = new FeatureDto();
        featureDto.mapFromSchema(doc);

        featureDto.flags.forEach((item) => {
          flagIds.push(new FlagDto({ featureFlagId: item.featureFlagId }));
          success = new SuccessFeatureResponseDto(featureDto.id, flagIds);
        });
        return new FeatureResponse(success, null);
      })
  }

Here's my FlagDto class

export class FlagDto {
  featureFlagId?: string;
  name: string;
}
1 Answers

$addToSet works best with scalars. In your case you will ned to run 2 queries:

Insert subdocument ($push) if it doesn't exists ($nin):

db.collection.update({
  <  your filter here  >
  "flags.name": {
    $nin: [
      < the name from FlagDto >
    ]
  }
},
{
  "$push": {
    "flags": < the FlagDto >
  }
})

Update ($set) the ones that exist (including the one inserted in the previous query)

db.collection.update({
  "flags.name": < the name from FlagDto >
},
{
  "$set": {
    "flags.$": < the FlagDto >
  }
})

Run both queries one after other (await the $push one to resolve) or pack them in a single ordered bulk write, which should be a little bit faster.

Related