Home > Mobile >  Mongoose update/insert value into array of objects
Mongoose update/insert value into array of objects

Time:02-07

So I have this data stored in a mongodb database:

{
    _id: 'string',
    email: 'string',
    purchases: [
        { name: 'item 1', cost: 45, quantity: 3 },
        { name: 'item 2', cost: 62, quantity: 2 },
        { name: 'item 3', cost: 14, quantity: 7 },
    ]
}

What I am trying to do is search for the user id (._id) and the item in the purchases array by the item name, so for item 1:

{ _id: req.body._id, purchases: { $elemMatch: { name: 'Item 1' }}}

This query works fine. However the behavior I need is if the item exists, modify the quantity value to reset to one. If the item doesn't exist, i.e. its a new item, I want to insert a new item object.

I thought that .findOneAndReplace would work for this, so my code is:

    User.findOneAndReplace(
        { _id: req.body._id, purchases: { $elemMatch: { name: 'Item 1' }}},
        { $push: { purchases: { name: req.body.name, cost: req.body.cost, quantity: 1 }}},
        {
            upsert: true
        }
    ).then((result) => {
        res.status(200).json({
            message: 'Added score :D'
        })
    }).catch((error) => {
        res.status(400).json({
            message: 'Failed to add score...'   error
        })
    })

but this obviously doesn't work. I can insert a new value into the purchases array but I cant update a current result if it exists.

CodePudding user response:

What you are doing is actually not a good way to handle documents.

A better way to handle your problem is to create a different model for purchases.

const purchases = mongoose.Schema({
      name: String,
      cost: Number,
      quantity: Number,
      user: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }
})

Instead of adding purchases to the User model, you will create a new entry under purchases.

To update purchases, you can just update each purchase document directly.

If you want to retrieve all purchases for a user, you can simply

 Purchases.find({ user: user._id })

To see if item exist.

 Purchases.find({ user: user._id, name: 'Item 1'});

You can also find the purchases through the user model using $lookup.

 Users.aggregate([
       {
          $match: { _id: user._id }
       },
       {
          $lookup: {
              from: 'purchases',
              localField: "_id",
              foreignField: "user",
              as: "purchases"
          }
       },
       {
          $project: {
               ....fields you want to return ....
          }
       }
 ])

In the long run you will find this model of database more efficient and easier to up keep, and there's more pros than cons separating the documents into different collections.

  •  Tags:  
  • Related