I am having hard time figuring out how to increment a value in an object within an array
我很难弄清楚如何在数组中的对象中递增一个值
For instance I have this document based on Poll
schema:
例如,我有一个基于轮询模式的文档:
{
"_id": "584b2cc6817758118e9557d8",
"title": "Number of Skittles",
"description": "Test1",
"date": "Dec 9, 2016",
"__v": 0,
"labelOptions": [
{
"Bob": 112
},
{
"Billy": 32
},
{
"Joe": 45
}
]
}
Using express, I am able to get this far:
使用Express,我能够走到这一步:
app.put('/polls/:id', function(req, res){
let id = req.params.id;
let labelOption = req.query.labelOption;
Poll.findOneAndUpdate(
{'_id' : id},
{$inc: {`labelOptions.$.${labelOption}`: 1 }},
function(err){
console.log(err)
})
where labelOption
is the one that I would like to increment its value
其中,LabelOption是我希望递增其值的选项
To be more concise, I am having trouble transversing inside the document.
更简洁地说,我在横切文档内部时遇到了困难。
更多回答
It is not possible to directly increment the value in the .find
query if labelOptions
is an Array of Object. To make it easier, you should change the labelOptions
type from Array of Objects to Object:
如果labelOptions是对象数组,则不可能在.find查询中直接递增该值。为方便起见,应将labelOptions类型从数组对象更改为对象:
"labelOptions": {
"Bob": 112,
"Billy": 32,
"Joe": 45
};
Also consider using .findByIdAndUpdate
instead of .findOneAndUpdate
if you are querying by the document's _id
. And then, you can achieve what you want by:
如果按文档的_id进行查询,还可以考虑使用.findByIdAndUpdate而不是.findOneAndUpdate。然后,您可以通过以下方式实现您想要的:
Poll.findByIdAndUpdate(
id,
{$inc: {`labelOptions.${labelOption}`: 1 }},
function(err, document) {
console.log(err);
});
UPDATE: If you are persistent on using Array of Objects for labelOptions
, there is a workaround:
更新:如果你坚持使用对象数组的labelOptions,有一个解决方案:
Poll.findById(
id,
function (err, _poll) {
/** Temporarily store labelOptions in a new variable because we cannot directly modify the document */
let _updatedLabelOptions = _poll.labelOptions;
/** We need to iterate over the labelOptions array to check where Bob is */
_updatedLabelOptions.forEach(function (_label) {
/** Iterate over key,value of the current object */
for (let _name in _label) {
/** Make sure that the object really has a property _name */
if (_label.hasOwnProperty(_name)) {
/** If name matches the person we want to increment, update it's value */
if (_name === labelOption) ++_label._name;
}
}
});
/** Update the documents labelOptions property with the temporary one we've created */
_poll.update({labelOptions: _updatedLabelOptions}, function (err) {
console.log(err);
});
});
There is another way to do this which allows a more flexible document model. If you add a field to your object like:
有另一种方法可以做到这一点,它允许更灵活的文档模型。如果将字段添加到对象中,如下所示:
{
"_id": "584b2cc6817758118e9557d8",
"title": "Number of Skittles",
"description": "Test1",
"date": "Dec 9, 2016",
"__v": 0,
"labelOptions": [
{
"name": "Bob",
"number": 112
},
{
"name": "Billy",
"number": 32
},
{
"name": "Joe"
"number": 45
}
]
}
Then you can do:
然后,您可以执行以下操作:
app.put('/polls/:id', function(req, res){
let id = req.params.id;
let labelOption = req.query.labelOption;
Poll.findOneAndUpdate(
{
'_id' : id,
'labelOptions.name': labelOption
},
{$inc: {
"labelOptions.$.number": 1
}},
function(err){
console.log(err)
})
});
People solved it but, if you use that for if element in array doesnt exits, a solution:
人们解决了这个问题,但是,如果您使用它来表示数组中的元素不存在,则会有一个解决方案:
app.put('/polls/:id', async function (req, res) {
let id = req.params.id;
let labelOption = req.query.labelOption;
const exits = await Poll.exists({ _id: id, "labelOptions.name": labelOption });
if (exits)
await Poll.updateOne(
{ _id: id, "labelOptions.name": labelOption },
{
$inc: {
"labelOptions.$.number": 1
}
}
);
else
await Poll.updateOne({ _id: id }, {
$push: {
labelOptions: {
name: labelOption,
number: 1
}
}
});
});
更多回答
我是一名优秀的程序员,十分优秀!