MongoDB:如何确定数组字段是否包含元素?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16198429/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 13:10:04  来源:igfitidea点击:

MongoDB: How to find out if an array field contains an element?

mongodb

提问by shargors

I have two collections. The first collection contains students:

我有两个收藏。第一个集合包含学生:

{ "_id" : ObjectId("51780f796ec4051a536015cf"), "name" : "John" }
{ "_id" : ObjectId("51780f796ec4051a536015d0"), "name" : "Sam" }
{ "_id" : ObjectId("51780f796ec4051a536015d1"), "name" : "Chris" }
{ "_id" : ObjectId("51780f796ec4051a536015d2"), "name" : "Joe" }

The second collection contains courses:

第二个集合包含课程:

{
        "_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")
        ]
}

Each course document contains studentsarray which has a list of students registered for the course. When a student views a course on a web page he needs to see if he has already registered for the course or not. In order to do that, when the coursescollection gets queried on the student's behalf, we need to find out if studentsarray already contains the student's ObjectId. Is there a way to specify in the projection of a find query to retrieve student ObjectIdfrom studentsarray only if it is there?

每个课程文档都包含一个students数组,其中包含为该课程注册的学生列表。当学生在网页上查看课程时,他需要查看他是否已经注册了该课程。为了做到这一点,当courses代表学生查询集合时,我们需要确定students数组是否已经包含学生的 ObjectId。有没有办法在查找查询的投影中指定仅当存在时才ObjectIdstudents数组中检索学生?

I tried to see if I could $elemMatch operator but it is geared towards an array of sub-documents. I understand that I could use aggregation framework but it seems that it would be on overkill in this case. Aggregation framework would probably not be as fast as a single find query. Is there a way to query course collection to so that the returned document could be in a form similar to this?

我试图查看是否可以使用 $elemMatch 运算符,但它适用于一系列子文档。我知道我可以使用聚合框架,但在这种情况下似乎有点矫枉过正。聚合框架可能不会像单个查找查询那样快。有没有办法查询课程集合,以便返回的文档可以采用与此类似的形式?

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

采纳答案by Asya Kamsky

[editbased on this now being possible in recent versions]

[基于此的编辑现在可以在最近的版本中进行]

[Updated Answer] You can query the following way to get back the name of class and the student id only if they are already enrolled.

【更新答案】只有在已经注册的情况下,才能通过以下方式查询取回班级名称和学生ID。

db.student.find({},
 {_id:0, name:1, students:{$elemMatch:{$eq:ObjectId("51780f796ec4051a536015cf")}}})

and you will get back what you expected:

你会得到你所期望的:

{ "name" : "CS 101", "students" : [ ObjectId("51780f796ec4051a536015cf") ] }
{ "name" : "Literature" }
{ "name" : "Physics", "students" : [ ObjectId("51780f796ec4051a536015cf") ] }

[Original Answer] It's not possible to do what you want to do currently. This is unfortunate because you would be able to do this if the student was stored in the array as an object. In fact, I'm a little surprised you are using just ObjectId() as that will alwaysrequire you to look up the students if you want to display a list of students enrolled in a particular course (look up list of Id's first then look up names in the students collection - two queries instead of one!)

[原始答案] 目前无法做您想做的事情。这是不幸的,因为如果学生作为对象存储在数组中,您将能够这样做。事实上,我对您只使用 ObjectId() 感到有些惊讶,因为如果您想显示注册特定课程的学生列表(首先查找 Id 列表,然后查找),它将始终要求您查找学生在学生集合中添加姓名 - 两个查询而不是一个!)

If you were storing (as an example) an Id and name in the course array like this:

如果您在课程数组中存储(例如)一个 Id 和名称,如下所示:

{
        "_id" : ObjectId("51780fb5c9c41825e3e21fc6"),
        "name" : "Physics",
        "students" : [
                {id: ObjectId("51780f796ec4051a536015cf"), name: "John"},
                {id: ObjectId("51780f796ec4051a536015d0"), name: "Sam"}
        ]
}

Your query then would simply be:

您的查询将是:

db.course.find( { }, 
                { students : 
                    { $elemMatch : 
                       { id : ObjectId("51780f796ec4051a536015d0"), 
                         name : "Sam" 
                       } 
                    } 
                } 
);

If that student was only enrolled in CS 101 you'd get back:

如果那个学生只注册了 CS 101,你会得到:

{ "name" : "Literature" }
{ "name" : "Physics" }
{
    "name" : "CS 101",
    "students" : [
        {
            "id" : ObjectId("51780f796ec4051a536015cf"),
            "name" : "John"
        }
    ]
}

回答by xbonez

It seems like the $inoperator would serve your purposes just fine.

似乎$in运营商可以很好地满足您的目的。

You could do something like this (pseudo-query):

你可以做这样的事情(伪查询):

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

Alternatively, you could remove the "course" : courseIdclause and get back a set of all classes the student is enrolled in.

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

回答by Anup

I am trying to explain by putting problem statement and solution to it. I hope it will help

我试图通过把问题陈述和解决方案来解释。我希望它会有所帮助

Problem Statement:

问题陈述:

Find all the published products, whose name like ABC Product or PQR Product, and price should be less than 15/-

查找所有已发布的产品,名称为 ABC 产品或 PQR 产品,且价格应小于 15/-

Solution:

解决方案:

Below are the conditions that need to be taken care of

以下是需要注意的条件

  1. Product price should be less than 15
  2. Product name should be either ABC Product or PQR Product
  3. Product should be in published state.
  1. 产品价格应低于15
  2. 产品名称应为 ABC 产品或 PQR 产品
  3. 产品应处于已发布状态。

Below is the statement that applies above criterion to create query and fetch data.

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

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