使用mongoose

时间:2018-10-05 13:59:23

标签: javascript node.js mongodb mongoose mongoose-schema

我正在尝试更新mongoDB中包含嵌套数组的文档。
情况如下:

我有一个newsItem模型,该模型可以包含一个轮询对象。此民意调查对象具有:标题,totalVotes和选项。 option是一个对象数组,这些对象包含:optionName和optionVotes。在每个这些对象中。 optionVotes是一个数组,其中包含对其进行投票的用户的ID。 (因为我想跟踪谁对什么以及我想防止两次投票进行表决)

所以它应该看起来像这样:

{
    "_id" : ObjectId("5bb7487727430319f5c18495"),
    "poll" : {
        "totalVotes" : 0,
        "title" : "test",
        "options" : [ 
            {
                "optionName" : "Burgers",
                "optionVotes" : []
            }, 
            {
                "optionName" : "Pizza",
                "optionVotes" : []
            }, 
            {
                "optionName" : "Fish",
                "optionVotes" : []
            }, 
            {
                "optionName" : "BBQ",
                "optionVotes" : []
            }, 
            {
                "optionName" : "Soup",
                "optionVotes" : []
            }, 
            {
                "optionName" : "Pasta",
                "optionVotes" : []
            }
        ]
    }
}

我现在想做的是,每当调用api路由/ news / votes /:id时,它将使用:id更新newsitem并将用户id放入给定的表决选项中。 (在体内) 因此,在请求中,我有:用户ID和投票的optionName

这是我目前无法使用的内容:

exports.vote = (req, res) => {
    News.findOneAndUpdate({ _id: req.params.id }).exec((err, newsItem) => {
        let tempItem = newsItem
        for (let i = 0; i < tempItem.poll.options.length; i++) {
            if (tempItem.poll.options[i].optionName === req.body.optionName) {
                tempItem.poll.options[i].optionVotes.push(req.user._id)
            }
        }
        console.log(tempItem.poll.options[0])
        tempItem.save(err => {
            if (!err) {
                return res.status(200).send()
            }
        })
    })
}

例如,当我这样做时,很奇怪:

tempitem.poll.title ='新标题' tempitem.save()

然后标题在数据库中得到更新! 代码中的console.log确实会输出正确的对象。

我也尝试使用更标准的方式:

findOneAndUpdate({ _id: req.param.id }, {$addToSet: {.....}}).exec(...)

但是我实际上不知道如何从数组中获取具有特定键的对象,然后更新该对象的一部分。

我正在考虑的其他2种选择:

  • 将整个民意调查对象提取到另一个文档,然后使用 在newsItem中引用。但这不能解决问题 两者之一(对SQL也有感觉)
  • 不将已投票用户的数组放在每个表决选项中,而是 所有投票者的用户数组。 ->缺点:我看不到 谁对什么投票。

1 个答案:

答案 0 :(得分:0)

由于您并未真正使用findOneAndUpdate(因为您未提供实际的更新),因此您可以简单地使用findOne并尝试执行以下操作:

exports.vote = (req, res) => {
    News.findOne({ _id: req.params.id }).exec(err, tempItem) => {
        let option = tempItem.poll.options.find(({optionName}) => optionName == req.body.optionName)
        option.optionVotes.push(req.user._id)
        console.log(option)

        tempItem.save(err => {
            if (!err) {
                return res.status(200).send()
            }
        })
    }
}

那是做到这一点的一种方法。我认为最好的方法是利用update部分,并将findOneAndUpdate与传入的更新对象一起使用。

像这样:

findOneAndUpdate({ 
   _id: req.param.id, 'poll.options.optionName': req.body.optionName
}, 
{ $addToSet: 
  { 'poll.options.$.optionVotes': req.user._id }
}).exec(...)