如何在MongoDB中查询嵌套的对象数组?

4
我正在尝试从Node.js查询MongoDB中的嵌套对象数组,尝试了所有解决方案,但没有成功。有人可以优先帮助一下吗?
我已经尝试了以下方法:
{
              "name": "Science",
              "chapters": [
                 {
                     "name": "ScienceChap1",
                     "tests": [
                        {
                            "name": "ScienceChap1Test1",
                            "id": 1,
                            "marks": 10,
                            "duration": 30,
                            "questions": [
                               {
                                   "question": "What is the capital city of New Mexico?",
                                   "type": "mcq",
                                   "choice": [
                                      "Guadalajara",
                                      "Albuquerque",
                                      "Santa Fe",
                                      "Taos"
                                   ],
                                   "answer": [
                                      "Santa Fe",
                                      "Taos"
                                   ]
                               },
                               {
                                   "question": "Who is the author of beowulf?",
                                   "type": "notmcq",
                                   "choice": [
                                      "Mark Twain",
                                      "Shakespeare",
                                      "Abraham Lincoln",
                                      "Newton"
                                   ],
                                   "answer": [
                                      "Shakespeare"
                                   ]
                               }
                            ]
                        },
                        {
                            "name": "ScienceChap1test2",
                            "id": 2,
                            "marks": 20,
                            "duration": 30,
                            "questions": [
                               {
                                   "question": "What is the capital city of New Mexico?",
                                   "type": "mcq",
                                   "choice": [
                                      "Guadalajara",
                                      "Albuquerque",
                                      "Santa Fe",
                                      "Taos"
                                   ],
                                   "answer": [
                                      "Santa Fe",
                                      "Taos"
                                   ]
                               },
                               {
                                   "question": "Who is the author of beowulf?",
                                   "type": "notmcq",
                                   "choice": [
                                      "Mark Twain",
                                      "Shakespeare",
                                      "Abraham Lincoln",
                                      "Newton"
                                   ],
                                   "answer": [
                                      "Shakespeare"
                                   ]
                               }
                            ]
                        }
                     ]
                 }
              ]
          }

这是我尝试过的,但仍然无法使其工作。
db.quiz.find({name:"Science"},{"tests":0,chapters:{$elemMatch:{name:"ScienceCh‌​ap1"}}})
db.quiz.find({ chapters: { $elemMatch: {$elemMatch: { name:"ScienceChap1Test1" } } }}) 
db.quiz.find({name:"Science"},{chapters:{$elemMatch:{$elemMatch:{name:"Scienc‌​eChap1Test1"}}}}) ({ name:"Science"},{ chapters: { $elemMatch: {$elemMatch: { name:"ScienceChap1Test1" } } }})

你尝试过哪些解决方案? - Abdullah Rasheed
  1. db.quiz.find({name:"Science"},{"tests":0,chapters:{$elemMatch:{name:"ScienceChap1"}}}).pretty()
  2. db.quiz.find({ chapters: { $elemMatch: {$elemMatch: { name:"ScienceChap1Test1" } } }})
  3. db.quiz.find({name:"Science"},{chapters:{$elemMatch:{$elemMatch:{name:"ScienceChap1Test1"}}}}) ({ name:"Science"},{ chapters: { $elemMatch: {$elemMatch: { name:"ScienceChap1Test1" } } }}) - 上面是我的样本JSON数据
- Arun Yegi
2个回答

4

聚合框架

您可以使用聚合框架将集合中的文档转换和组合以供客户端显示。您需要构建一个处理文档流的管道,通过多个构建块进行过滤、投影、分组、排序等操作。

如果您想从名为“ScienceChap1Test1”的测试中获取MCQ类型的问题,则应执行以下操作:

db.quiz.aggregate(
    //Match the documents by query. Search for science course
    {"$match":{"name":"Science"}},

    //De-normalize the nested array of chapters.
    {"$unwind":"$chapters"},
    {"$unwind":"$chapters.tests"},

    //Match the document with test name Science Chapter
    {"$match":{"chapters.tests.name":"ScienceChap1test2"}},

    //Unwind nested questions array
    {"$unwind":"$chapters.tests.questions"},

    //Match questions of type mcq
    {"$match":{"chapters.tests.questions.type":"mcq"}}
).pretty()

结果将会是:
{
    "_id" : ObjectId("5629eb252e95c020d4a0c5a5"),
    "name" : "Science",
    "chapters" : {
        "name" : "ScienceChap1",
        "tests" : {
            "name" : "ScienceChap1test2",
            "id" : 2,
            "marks" : 20,
            "duration" : 30,
            "questions" : {
                "question" : "What is the capital city of New Mexico?",
                "type" : "mcq",
                "choice" : [
                    "Guadalajara",
                    "Albuquerque",
                    "Santa Fe",
                    "Taos"
                ],
                "answer" : [
                    "Santa Fe",
                    "Taos"
                ]
            }
        }
    }
}

$elemMatch不能用于子文档。你可以使用聚合框架通过使用$unwind进行“数组过滤”。

您可以从聚合管道中的每个命令底部删除每行以观察管道的行为。


非常感谢@inspired,你的帮助对我很大。真的非常感激你的帮助。请问你能告诉我如何在同一语句中应用更新/删除查询吗? - Arun Yegi
如果我想更新上面问题的答案,应该使用什么查询语句?让我们把问题本身作为find()函数的查询条件。 - Arun Yegi
@ArunYegi,您还需要查询方面的帮助吗? - Abdullah Rasheed
是的,@inspired。这将会很有帮助。 - Arun Yegi
查询语句中必须有数组封装标签,例如db.quiz.aggregate([{"$match":{"name":"Science"}}]} - jasmeetsohal

0

您应该在MongoDB简单的JavaScript shell中尝试以下查询。

可能有两种情况。

情况一

如果您只想返回包含某些章节名称或测试名称的文档,例如在find中只需一个参数即可。

对于find方法,要返回的文档由第一个参数指定。您可以通过执行以下操作返回名称为Science的文档:

db.quiz.find({name:"Science"})

您可以使用$elemMatch指定用于匹配数组中单个嵌入式文档的条件。要查找具有名称为ScienceChap1的章节的文档,可以执行以下操作:

db.quiz.find({"chapters":{"$elemMatch":{"name":"ScienceChap1"}}})

如果您想将您的条件设置为测试名称,则可以使用点运算符,如下所示:
db.quiz.find({"chapters.tests":{"$elemMatch":{"name":"ScienceChap1Test1"}}})

场景二 - 指定返回的键

如果您想指定要返回的键,可以向 find(或 findOne)传递第二个参数,指定您想要的键。在您的情况下,您可以搜索文档名称,然后提供要返回的键,如下所示。

db.quiz.find({name:"Science"},{"chapters":1})

//Would return
{
    "_id": ObjectId(...),
    "chapters": [
        "name": "ScienceChap2",
        "tests: [..all object content here..]
}

如果您只想返回每个测试对象的“标记”,则可以使用点运算符来实现:
db.quiz.find({name:"Science"},{"chapters.tests.marks":1})

//Would return
{
    "_id": ObjectId(...),
    "chapters": [
        "tests: [
            {"marks":10},
            {"marks":20}
         ]
}

如果你只想返回每个测试的问题

db.quiz.find({name:"Science"},{"chapters.tests.questions":1})

试试这些。希望能对你有所帮助。


感谢 @inspired。我查询了 'db.quiz.find({name:"Science","chapters.tests.questions.type":"mcq"},{"chapters.tests.questions.question":1}).pretty()' 来获取 mcq 类型的问题,理想情况下我应该只得到一个问题 - "新墨西哥州的首府是什么?" 但我得到了两个问题 - "问题": "新墨西哥州的首府是什么?","问题": "《贝奥武夫》的作者是谁?"。过滤没有发生。请帮忙。提前致谢。 - Arun Yegi
@ArunYegi 看看我的新答案。如果有任何问题,请告诉我。 - Abdullah Rasheed

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接