Mongodb 通过Mongoose.js中的ObjectId选择和更新嵌套对象
我在MongoDB和Mongoose中遇到了一些被认为是微不足道的问题 使用这样一个相当简单的模式Mongodb 通过Mongoose.js中的ObjectId选择和更新嵌套对象,mongodb,mongoose,Mongodb,Mongoose,我在MongoDB和Mongoose中遇到了一些被认为是微不足道的问题 使用这样一个相当简单的模式 const UserSchema = new Schema({ groups: [ { name: String, members: [ { hasAccepted: { type: Boolean } }
const UserSchema = new Schema({
groups: [
{
name: String,
members: [
{
hasAccepted: {
type: Boolean
}
}
]
}
]
});
当我创建新组时,每个成员对象当然都会获得一个_id属性。我只想通过其_id选择该成员并更新其hasAccept属性
当我使用成员的_id运行查询时,我会为用户返回整个记录,这使得很难找到嵌套成员来更新它
如何将结果精简为仅包含找到的ID的成员并更新其属性
我正在使用Mongo 3.6.2,并尝试了新的ArrayFilter,但运气不佳
下面是我使用节点的代码,它返回整个文档,但没有更新任何内容
const query = {
groups : {
$elemMatch : { members : { $elemMatch : {_id : <id>} } }
}
};
const update = {$set: {'groups.$[].members.$[o].hasAccepted':true }};
const options = { new: true, arrayFilters:[{"o._id":<id>}] };
// Find the document
User.findOneAndUpdate(query, update, options, function(error, result) {
if (error) {
res.send(error);
} else {
res.send(result);
}
});
感谢您提供的任何帮助。您可以尝试在下面的聚合中仅筛选组和成员数组中匹配的组和成员 将_id替换为要搜索的id,使用结果更新hasAccepted状态
db.groups.aggregate(
[
{$addFields : {"groups" : {$arrayElemAt : [{$filter : {input : "$groups", as : "g", cond : {$in : [_id, "$$g.members._id"]}}}, 0]}}},
{$addFields : {"groups.members" : {$filter : {input : "$groups.members", as : "gm", cond : {$eq : [_id, "$$gm._id"]}}}}}
]
).pretty()
好的,我需要更好地理解的是数组过滤器,我需要将组名添加到数据中,以获得需要更新的值 帮助我更好地理解arrayFilters的一件事是将其视为一种子查询,就像SQL世界中使用的一样。一旦我得到了,我就能够想出如何写我的更新 这篇文章对于理解如何使用ArrayFilter也很有帮助: 这是对我有用的代码。请注意,您需要Mongo3.6和Mongoose 5.0.0才能获得对ArrayFilter的支持 另外,您需要确保像这样要求Mongoose的ObjectId
const ObjectId = require('mongoose').Types.ObjectId;
以下是工作代码的其余部分:
const query = {
groups : {
$elemMatch : { members : { $elemMatch : {_id : new ObjectId("theideofmymemberobject"), hasAccepted : false} } }
}
};
const update = {$set: {'groups.$[group].members.$[member].hasAccepted':true } };
const options = { arrayFilters: [{ 'group.name': 'Group 3' },{'member._id': new ObjectId("theideofmymemberobject")}] };
// update the document
User.update(query, update, options, function(error, result) {
if (error) {
res.send(error);
} else {
res.send(result);
}
});
您知道该成员所属的组的名称吗?或者您只知道该成员的id?我知道名称,是的。这有帮助吗?好吧,我还没有真正使用聚合技术,但只有几周的时间使用Mongo本身,所以我不完全理解代码。当我在替换真实objectid后从mongo提示符运行该命令时,我没有得到任何返回-没有错误,没有结果,只是再次得到命令提示符。ok np,您可以发布查询和您尝试过的示例文档吗?您还可以发布您执行的查询吗?这是我根据您的答案使用的:db.groups.aggregate[{$addFields:{groups:{$arrayElemAt:[{$filter:{$groups,as:g,cond:{$in:[5A753F168B7F0231AB0621,$$g.members.{$id]}}}},0]}},{$addFields:{groups.members:{$filter:{input:$groups.members,as:gm,cond:{$eq:[5A753F168B5B5F0231AB0621,$$gm.{$id]}}能否尝试在查询中使用ObjectD5A753B553B17B53B7F0231AB0621而不是字符串?
const query = {
groups : {
$elemMatch : { members : { $elemMatch : {_id : new ObjectId("theideofmymemberobject"), hasAccepted : false} } }
}
};
const update = {$set: {'groups.$[group].members.$[member].hasAccepted':true } };
const options = { arrayFilters: [{ 'group.name': 'Group 3' },{'member._id': new ObjectId("theideofmymemberobject")}] };
// update the document
User.update(query, update, options, function(error, result) {
if (error) {
res.send(error);
} else {
res.send(result);
}
});
// An easier more modern way to do this is to pass a wildcard such as /:id in your API endpoint
// Use Object.assign()
// use the save() method
// If you are using JWT
// Otherwise find another unique identifier
const user = UserSchema.findOne({ id: req.user.id });
for (const oldObject of user.groups) {
if(oldObject.id === req.params.id) {
newObject = {
propertyName: req.body.val,
propertyName2: req.body.val2,
propertyName3: req.body.val3
}
// Update the oldObject
Object.assign(oldObject, newObject);
break;
}
}
user.save()
res.json(user);