我有一个MongoDB集合,格式为:
users: {
{
user_id: 1000,
activities: [
{id: 1, activity: 'swimming'},
{id: 2, activity: 'running'},
{id: 3, activity: 'biking'},...
]
},...
}
并且我想要获得与特定ID匹配的活动文档。例如,如果我使用{id: 1}
进行查询,我想要{id: 1, activity: 'swimming'}
的输出。目前,我正在尝试使用findOne({activities: {$elemMatch: {id: 1}}})
,但它返回了整个用户文档(用户id和所有活动)。
我使用的代码是:
id = req.body.queryID;
db.collection('users').findOne({activities: {$elemMatch: {id}}})
.then((document) => {
console.log(document);
// more code after this
});
我也尝试过使用aggregate()
和findOne({}, {activities: {$elemMatch: {id}}})
进行查询,但一直无法解决。
根据db.version()
,我使用的是MongoDB 4.4.8版本。感谢您的帮助!
你的尝试看起来很接近,我认为你只需要把它们放在一起。findOne
采用两个可选参数,一个查询和一个投影。查询告诉MongoDB要查找和返回什么文档。投影文档告诉MongoDB在查询返回的文档中包含哪些字段。
这里有什么:
db.collection('users').findOne({ activities: { $elemMatch: { id }}})
传递一个参数,即查询。它将查找一个文档,其中activities
数组中有一个元素的id
等于变量id
的值。你也可以这样写:
db.collection('users').findOne({ "activities.id": id })
您还希望只返回activities
数组中具有匹配ID的文档。这是您进行类似于其他尝试的操作的时候,其中$elemMatch
位于第二个参数中,即投影:
db.collection('users').findOne({}, {activities: {$elemMatch: {id}}})
但是,因为您传递了一个空查询,MongoDB将返回任何文档,而不一定是包含具有匹配ID的活动的文档。
所以,如果你同时通过了一个查询和投影,我认为你应该得到你想要的。它可能看起来像这样:
db.collection('users').findOne({ "activities.id": id }, { activities: { $elemMatch: { id }}})
这将仅包括_id
字段和匹配的activities
文档(如果存在)。如果要包含文档的其他字段,则需要显式包含这些字段。请参阅有关投影的文档。
您可以将aggregate
方法与unwind
、match
和project
管道一起使用
db.users.aggregate([
{$unwind: "$activities"},
{$match: {"activities.id": id}},
{$project: {id: "$activities.id", activity: "$activities.activity", _id: 0}}
])
注意:此代码是使用mongoshell语法编写的。
查询执行以下
- 从
unwind
管道开始,该管道首先提取活动数组中的所有项 match
管道查找具有我们要查找的id的数组元素project
管道根据需要返回输出
希望这能帮助
请按如下方式尝试:
db.users.aggregate([
{
'$unwind': '$activities'
}, {
'$match': {
'id': id
}
}, {
'$project': {
'activity': '$activities.activity',
'id': '$activities.id',
'_id':0
}
}
]);