简体   繁体   English

mongoose updateOne with upsert 不工作

[英]mongoose updateOne with upsert is not working

let cart = req.body.params.cart // array of objects that needs to be updated if exists in db, if not upsert it. 

let userid = req.body.params.uid

for (let i = 0; i < cart.length; i++) {
    Cart.updateOne({ user: userid, 'cart.product': cart[i].product._id },
        {
            $set: {
                'cart.$.quantity': cart[i].quantity
            }
        },
        { upsert: true }// works without this line of code, updates the objects if exists
    )
}

my cart model:我的购物车 model:

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const CartSchema = new Schema({
    user: {
        type: Schema.Types.ObjectId,
        ref: 'users'
    },
    cart: [{
        product: {
            type: Schema.Types.ObjectId,
            ref: 'productlist'
        },
        quantity: {
            type: Number
        },
        date: {
            type: Date,
            default: Date.now
        }
    }]

})

module.exports = Cart = mongoose.model('cart', CartSchema)

I'm trying to update a users shopping cart with new items that are in the cart array.我正在尝试使用购物车数组中的新商品更新用户购物车。 I need to check if product exists, if yes update quantity, if not push it in to user's cart.我需要检查产品是否存在,如果是更新数量,如果不将其推入用户的购物车。 Somehow it doesnt work with $upsert.不知何故,它不适用于 $upsert。 without $upsert document gets updated if object id exists in the user's cart.如果 object id 存在于用户的购物车中,则不更新 $upsert 文档。

Working version with tons of clutter.有大量杂乱的工作版本。 I feel like there is a better way of doing it like the one I was trying to do above.我觉得有一种更好的方法可以做到这一点,就像我在上面尝试做的那样。 I would appriceate any help, reducing clutter here.我会感谢任何帮助,减少这里的混乱。

Cart.find({ user: req.body.params.uid })
        .then(userCart => {
            if (userCart[0].cart.length === 0) {
                for (let i = 0; i < cart.length; i++) {
                    Cart.updateOne({ user: req.body.params.uid }, {
                        $push: {
                            cart: {
                                product: cart[i].product._id,
                                quantity: cart[i].quantity
                            }
                        }
                    }).catch(err => console.log(err))
                }
            }
            else {

                cart.reduce((acc, element) => {
                    let index = userCart[0].cart.findIndex(val => val.product._id == element.product._id)
                    if (index !== -1) {

                        Cart.findOneAndUpdate({ user: req.body.params.uid, 'cart.product': element.product._id },
                            {
                                $set: {
                                    'cart.$.quantity': element.quantity
                                }
                            },
                            { new: true }
                        ).then(a => console.log(a))
                    }
                    else {
                        Cart.updateOne({ user: req.body.params.uid }, {
                            $push: {
                                cart: {
                                    product: element.product._id,
                                    quantity: element.quantity
                                }
                            }
                        }).catch(err => console.log(err))
                    }
                    acc.push(element)
                    return acc
                }, [])
            }
        })

Sample value from array cart来自数组购物车的样本值

   product: {
     _id: '5eaf8eeac436dbc9b7d75f35',
     name: 'Strawberry',
     category: 'organic',
     image: '/productImages/australian.jpg',
     price: '9.65'
   },
   quantity: 6

sample cart in db:数据库中的样品车:

   _id: 5ec12ea36ccf646ff5aeef0c,
   user: 5ec11a8f69ccf46e0e19c5ef,
   cart: [
     {
       date: 2020-05-18T10:26:38.751Z,
       _id: 5ec262de5829f081b1ea96d7,
       product: 5eaf8eeac436dbc9b7d75f35,
       quantity: 8
     },
     {
       date: 2020-05-18T12:11:57.168Z,
       _id: 5ec27b8dd2949886308bebd6,
       product: 5eaf8f61c436dbc9b7d75f36,
       quantity: 6
     }
   ]

I think the best solution is to match the old cart and new cart first in the node.js code then update it, for that below are the steps and code.我认为最好的解决方案是首先在 node.js 代码中匹配旧购物车和新购物车然后更新它,因为下面是步骤和代码。

  1. Create an array of only productid and their quantity from the new cart从新购物车中创建一个仅包含 productid 及其数量的数组
  2. Then fetch the old cart details from database然后从数据库中获取旧的购物车详细信息
  3. Match both the cart and create two different array one which will only contain the products which are new in the cart, and one other which will contain the productid already there in the old cart匹配购物车并创建两个不同的数组,一个仅包含购物车中的新产品,另一个包含旧购物车中已有的 productid

Now you have two separate arrays which will be easy to update in 2 queries only, instead of the loop or multiple queries you are using in your code.现在您有两个单独的 arrays 将很容易仅在 2 个查询中更新,而不是您在代码中使用的循环或多个查询。 I also tried to explain it in code comments.我也尝试在代码注释中解释它。

// First get all the new cart productid and quantity in an array
var cartArray = cart.map(obj => {
    return {product: obj.product._id, quantity: obj.quantity}
})

Cart.findOne({ user: req.body.params.uid })
   .then(userCart => {

var productIds = userCart.cart.map(obj => obj.product)

// array of products id and quantity which are already there in old cart
var productsOld = cartArray.filter(obj => {
  return productIds.includes(obj.product)
})

// array of products id and quantity which are not there in old cart
var productsNew = cartArray.filter(obj => {
  return !productIds.includes(obj.product)
})

//First, we will add the all new products which are in the new cart
Cart.findOneAndUpdate({ user: req.body.params.uid }, {
  $push: {
    cart: {
      $each: productsNew
    }
  }
}, {
  new: true
}).then(function(updatedUserCart){
  // Here we are getting now the updated cart with new products added
  // Now we need to update quantity of old products

  // Instead of running query in loop, we will update the quantity in array map
  // and replace the whole cart in the document
  var newCart = updatedUserCart.cart.map(obj => {
    var matchProduct = productsOld.filter(oldObj => {
      return oldObj.product == obj.product
    })
    if (matchProduct.length > 0) {
      obj.quantity = parseInt(obj.quantity) + parseInt(matchProduct[0].quantity)
      return obj
    } else {
      return obj
    }
  })

  Cart.updateOne({ user: req.body.params.uid }, {
      $set: {
          cart: newCart
      }
  })
}).catch(err => console.log(err))
})

Disclaimer: I haven't tried to run the code on my system, so there may be a typo or syntax error, but I hope you understand the flow and logic免责声明:我没有尝试在我的系统上运行代码,因此可能存在拼写错误或语法错误,但希望您了解流程和逻辑

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM