猫鼬updateOne与upsert不起作用

时间:2020-05-18 11:24:33

标签: javascript node.js mongodb mongoose

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
    )
}

我的购物车型号:

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)

我正在尝试使用购物车数组中的新商品更新用户的购物车。我需要检查产品是否存在,如果是,则更新数量,如果没有,则将其推入用户的购物车。不知何故,它与$ upsert不兼容。如果用户购物车中存在对象ID,则没有$ upsert文档的文档将被更新。

工作版本充满混乱。我觉得有一种更好的方法可以像我上面试图做的那样。我会尽量提供帮助,以减少混乱。

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
                }, [])
            }
        })

阵列购物车中的样本值

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

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
     }
   ]

1 个答案:

答案 0 :(得分:0)

我认为最好的解决方案是先在node.js代码中匹配旧购物车和新购物车,然后对其进行更新,以下是步骤和代码。

  1. 从新购物车中创建仅包含productid及其数量的数组
  2. 然后从数据库中获取旧的购物车详细信息
  3. 匹配购物车并创建两个不同的数组,一个数组将仅包含购物车中的新产品,另一个将包含旧购物车中已经存在的productid。

现在,您有两个单独的数组,仅在2个查询中即可轻松更新它们,而无需在代码中使用循环或多个查询。我还尝试在代码注释中对此进行解释。

// 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))
})

免责声明:我没有尝试在系统上运行代码,因此可能存在拼写错误或语法错误,但是希望您能理解流程和逻辑