How to upsert in an array

My current data looks like:

{Id: 0,
name: “apple”,
market: [
{
name: “a”, price: 18, type: “b”},
{name: “b”, price: 20, type: “c”}
]}

If I would like to push {name: “c”, price: 30, type: “d”} into the market which name = "apple”, what should I do in mongoose? but if there is already has name="c” and type = "d” inside the market array, I will update the existing data instead of pushing new data, I am using typescript and mongoose.

Hi @WONG_TUNG_TUNG, so there are two approaches to this, the way simpler version (works for almost all use-cases) and then the performance-aware version (overly complex, only use if you are trying to be as performant as possible)

Simpler version - just mutate the data as you would an object and then save in typescript, and since you are using mongoose, it’s way easier -

const doc = await YourModel.findOne({ name: "apple" });

if (!doc) {
    return;
}

const existingItem = doc.market.find(item => item.name === "c" && item.type === "d");

if (existingItem) {
  existingItem.price = 30;
} else {
  doc.market.push({ name: "c", price: 30, type: "d" });
}

await doc.save();

Complex version - usually for memory-sensitive or performance-sensitive use-cases:

await YourModel.updateOne(
  { 
    name: "apple",
    "market.name": { $ne: "c" },
    "market.type": { $ne: "d" }
  },
  {
    $push: {
      market: { name: "c", price: 30, type: "d" }
    }
  }
);

await YourModel.updateOne(
  { 
    name: "apple",
    "market.name": "c",
    "market.type": "d"
  },
  {
    $set: {
      "market.$.price": 30
    }
  }
);

Hope this helps!

1 Like

in this solution, I need perform two insertion, one is the not equal(not existing) case to push the data, another is the equal(existing) case to update the data right? I thought there will be one command/function to achieve it instead of two

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.