MongoDB: 如何找出一个数组字段是否包含一个元素?

我有两个收藏。第一个收藏包括学生:

{ "_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数组,其中有一个注册该课程的学生名单。当一个学生在网页上查看一门课程时,他需要知道他是否已经注册了这门课程。为此,当代表学生查询 courses集合时,我们需要查明 students数组是否已经包含学生的 ObjectId。是否有一种方法可以在查找查询的投影中指定,只有在 students数组存在的情况下才从 ObjectId中检索学生?

我试图查看是否可以使用 $elemMatch 运算符,但它面向的是子文档数组。我知道我可以使用聚合框架,但是在这种情况下似乎有些过头了。聚合框架可能不会像单个查询那样快。是否有一种方法可以查询课程集合,以便返回的文档可以采用与此类似的形式?

{
"_id" : ObjectId("51780fb5c9c41825e3e21fc4"),
"name" : "CS 101",
"students" : [
ObjectId("51780f796ec4051a536015d0"),
]
}
169775 次浏览

看起来 $in操作员可以很好地满足您的需求。

您可以这样做(伪查询) :

if (db.courses.find({"students" : {"$in" : [studentId]}, "course" : courseId }).count() > 0) {
// student is enrolled in class
}

或者,您可以删除 "course" : courseId子句,并返回该学生已注册的所有课程的集合。

[ 编辑的基础上,现在可能在最近的版本]

[更新答案]你可以通过以下方式查询,只有当他们已经注册时才能得到班级名称和学生证。

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/-

解决方案:

以下是需要注意的条件

  1. 产品价格应低于15
  2. 产品名称应该是 ABC 产品或 PQR 产品
  3. 产品应该处于发布状态。

下面是应用上述条件创建查询和获取数据的语句。

$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
)
);