以下是我的user
和product
架构:
const productSchema = new Schema({
//...
addedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: "users"
}
});
const userSchema = new Schema({
//...
addedItems: [{
type: mongoose.Schema.ObjectId,
ref: "products"
}]
});
mongoose.model("products", productSchema);
mongoose.model("users", userSchema);
在我的Node后端路由中,我执行以下查询:
User.findOneAndUpdate(
{ _id: req.body.id },
{ $push: { addedItems: newProduct._id } },
{ upsert: true, new: true },
function(err, doc) {
console.log(err, doc);
}
);
console.log
打印出来:
{
//...
addedItems: [ 5ab0223118599214f4dd7803 ]
}
一切看起来都不错。我实际上使用前端网站查看我的mongo db的数据;我正在使用mlab.com,这就是显示的内容:
{
//...
"addedItems": [
{
"$oid": "5ab0223118599214f4dd7803"
},
{
"$oid": "5ab0223118599214f4dd7803"
}
]
}
问题:发生了什么事?为什么要在addedItems中添加额外的条目?即使我的console.log只显示了一个。
注意:
我测试了后端路由是否被多次调用。它不是。
$push
似乎有问题,因为如果我只有{ addedItems: newProduct._id }
,那么只有一个条目进入,但它会覆盖整个数组。
修改
制作一个测试项目以产生相同的结果:https://github.com/philliprognerud/test-mcve-stackoverflow
有人能弄清楚发生了什么吗?
答案 0 :(得分:6)
问题是由于您使用了promises(通过async / await)和使用findOneAndUpdate
调用的回调混合使用,最终执行了两次命令。
解决问题:
const updatedUser = await User.findOneAndUpdate(
{ id: userID },
{ $push: { addedItems: newProduct.id } },
{ upsert: true, new: true }
);
console.log(updatedUser);
未来的读者注意到问题中没有显示await
的使用,但是在MCVE中。
答案 1 :(得分:1)
此代码$ push不断添加两个条目: const ali = {“ _id”:“ 5eaa39a18e7719140e3f4430”};
// return await customerModel.findOneAndUpdate(
// ali,
// {
// "$push": {
// "address": [objAdr],
// },
// },
// function (error: any, success: any) {
// if (error) {
// console.log(error);
// } else {
// console.log(success);
// }
// }
// );
我的解决方案工作正常:
return await customerModel
.findOneAndUpdate(
{ _id: ids },
{ $push: { "address": objAdr } }
)
.catch((err: string | undefined) => new Error(err));
答案 2 :(得分:0)
我正面临类似的问题。刚登陆到此页面。我发现先前的答案不是很具描述性。所以发布这个:
export const updateUserHandler = async (req, res) => {
const request = req.body;
await User.findOneAndUpdate( //<== remove await
{ _id: request.id },
{ $push: { addedItems: newProduct._id } },
{ upsert: true, new: true },
(findErr, findRes) => {
if (findErr) {
res.status(500).send({
message: 'Failed: to update user',
IsSuccess: false,
result: findErr
});
} else {
res.status(200).send({
message: 'Success: to update user',
IsSuccess: true,
result: findRes
});
}
}
);
}
这里有两个异步调用,一个是 async ,另一个是 await 。因此,文档中有两个条目。只需从 await User.findOneAndUpdate中删除await。它将完美运行。 谢谢!
答案 3 :(得分:0)
在等待查询时,您使用的是类似诺言的查询,特别是Query的.then()
和.catch(()
。同时传递回调也会导致您描述的行为。
如果同时等待查询和查询的.then()
,则会使查询执行两次
使用:
await Model.findOneAndUpdate(query, doc, options)
OR
Model.findOneAndUpdate(query, doc, options, callback)