MongoDB:如何确定数组字段是否包含元素?
我有两个收藏。第一个集合包含学生:MongoDB:如何确定数组字段是否包含元素?,mongodb,Mongodb,我有两个收藏。第一个集合包含学生: { "_id" : ObjectId("51780f796ec4051a536015cf"), "name" : "John" } { "_id" : ObjectId("51780f796ec4051a536015d0"), "name" : "Sam" } { "_id" : ObjectId("51780f796ec4051a536015d1"), "name" : "Chris" } { "_id" : ObjectId("51780f796ec405
{ "_id" : ObjectId("51780f796ec4051a536015cf"), "name" : "John" }
{ "_id" : ObjectId("51780f796ec4051a536015d0"), "name" : "Sam" }
{ "_id" : ObjectId("51780f796ec4051a536015d1"), "name" : "Chris" }
{ "_id" : ObjectId("51780f796ec4051a536015d2"), "name" : "Joe" }
第二个系列包含以下课程:
{
"_id" : ObjectId("51780fb5c9c41825e3e21fc4"),
"name" : "CS 101",
"students" : [
ObjectId("51780f796ec4051a536015cf"),
ObjectId("51780f796ec4051a536015d0"),
ObjectId("51780f796ec4051a536015d2")
]
}
{
"_id" : ObjectId("51780fb5c9c41825e3e21fc5"),
"name" : "Literature",
"students" : [
ObjectId("51780f796ec4051a536015d0"),
ObjectId("51780f796ec4051a536015d0"),
ObjectId("51780f796ec4051a536015d2")
]
}
{
"_id" : ObjectId("51780fb5c9c41825e3e21fc6"),
"name" : "Physics",
"students" : [
ObjectId("51780f796ec4051a536015cf"),
ObjectId("51780f796ec4051a536015d0")
]
}
每个课程文档都包含students
数组,其中包含注册课程的学生列表。当学生在网页上查看课程时,他需要查看是否已注册该课程。为此,当代表学生查询课程
集合时,我们需要确定学生
数组是否已经包含学生的ObjectId。是否有一种方法可以在find查询的投影中指定仅当存在时才从students
数组中检索studentObjectId
我试图看看是否可以使用$elemMatch操作符,但它面向一系列子文档。我知道我可以使用聚合框架,但在这种情况下,它似乎有点过头了。聚合框架可能不会像单个查找查询那么快。是否有一种方法可以查询课程集合,以便返回的文档的形式与此类似
{
"_id" : ObjectId("51780fb5c9c41825e3e21fc4"),
"name" : "CS 101",
"students" : [
ObjectId("51780f796ec4051a536015d0"),
]
}
看来接线员能很好地为你服务
您可以这样做(伪查询):
或者,您可以删除
“course”:courseId
子句,并取回该学生注册的所有课程的集合。[基于此,现在可以在最新版本中进行编辑]
[更新的答案]只有在已经注册的情况下,您可以通过以下方式查询以获取班级名称和学生id
db.student.find({},
{_id:0, name:1, students:{$elemMatch:{$eq:ObjectId("51780f796ec4051a536015cf")}}})
你会得到你所期望的:
{ "name" : "CS 101", "students" : [ ObjectId("51780f796ec4051a536015cf") ] }
{ "name" : "Literature" }
{ "name" : "Physics", "students" : [ ObjectId("51780f796ec4051a536015cf") ] }
[原始答案]目前不可能做你想做的事情。这是不幸的,因为如果学生作为对象存储在数组中,您就可以这样做。事实上,我有点惊讶您使用的是ObjectId(),因为如果您想显示某一特定课程的注册学生列表,那么您总是需要查找学生(首先查找Id列表,然后在学生集合中查找姓名-两个查询而不是一个查询!)
如果在课程数组中存储(例如)Id和名称,如下所示:
{
"_id" : ObjectId("51780fb5c9c41825e3e21fc6"),
"name" : "Physics",
"students" : [
{id: ObjectId("51780f796ec4051a536015cf"), name: "John"},
{id: ObjectId("51780f796ec4051a536015d0"), name: "Sam"}
]
}
那么,您的问题就是:
db.course.find( { },
{ students :
{ $elemMatch :
{ id : ObjectId("51780f796ec4051a536015d0"),
name : "Sam"
}
}
}
);
如果该学生只注册了CS 101,你会得到:
{ "name" : "Literature" }
{ "name" : "Physics" }
{
"name" : "CS 101",
"students" : [
{
"id" : ObjectId("51780f796ec4051a536015cf"),
"name" : "John"
}
]
}
我试图通过问题陈述和解决方案来解释。我希望这会有所帮助 问题陈述: 查找所有已发布的产品,其名称如ABC产品或PQR产品,且价格应小于15/- 解决方案: 以下是需要注意的情况
$elements = $collection->find(
Array(
[price] => Array( [$lt] => 15 ),
[$or] => Array(
[0]=>Array(
[product_name]=>Array(
[$in]=>Array(
[0] => ABC Product,
[1]=> PQR Product
)
)
)
),
[state]=>Published
)
);
这种方法的问题是,只有学生注册了课程,它才会返回课程集合中的文档。如果学生尚未注册,则需要进行第二次查询。这是无效的。第二个查询是检索学生的对象id吗?但这不是已经知道了吗(毕竟,您正在使用它进行第一次查询)。最终目标是检索课程文档,并有一个标志指示学生是否已注册。您提供的查询将仅在学生已注册的情况下检索课程文档。如果学生没有注册课程,则需要另一个查询来检索课程文档。我认为数据模型没有任何问题。我怀疑没有两个问题就没有真正的方法来实现你想要的,因为在一天结束时,你会问你的数据库两个问题:给我课程文档,学生是否参加了课程。即使在传统的关系数据库中,您也会面临同样的问题。延迟响应(抱歉!),但这从来不是Mongo的目标。Mongo用于存储非关系、无模式的数据对象。好吧,它没有试图减少所需的查询数量。感谢您确认我关于不能查询简单数组以及子文档数组的想法。我想我必须重新评估我的模式。你知道10Gen是否计划解决这个问题吗?我在Jira.mongodb.org上找不到这个问题的Jira票证,没有票证的情况下,任何东西都不会被安排发布,所以我想说肯定不会很快。使用$all中描述的$all是查询的操作员-查询不是问题,这个问题又回来了,所以我们讨论的是投影操作符。在
课程
集合中同时存储名称和对象id的问题是,学生名称存储在多个位置,这可能会失去同步。在这种情况下,查询将返回不完整的数据。如果服务器负载和硬件不是很紧,那么最好使用额外的查询来获取名称。您仍然可以将studentObjectId
s存储为object以允许OP的查询:{“id”:…}
$elements = $collection->find(
Array(
[price] => Array( [$lt] => 15 ),
[$or] => Array(
[0]=>Array(
[product_name]=>Array(
[$in]=>Array(
[0] => ABC Product,
[1]=> PQR Product
)
)
)
),
[state]=>Published
)
);