MongoDb - 在嵌套数组中查找特定的 obj
Posted
技术标签:
【中文标题】MongoDb - 在嵌套数组中查找特定的 obj【英文标题】:MongoDb - Find a specific obj within nested arrays 【发布时间】:2016-01-30 02:22:15 【问题描述】:我希望有人能对我遇到的这个问题有所了解,这让我发疯了,过去三天我一直在学习越来越多的关于 mongoDB 的知识,但仍然无法弄清楚这个简单的查询.
我需要做的是获取包含“carId”=“3C”的对象。
换句话说,我希望查询返回的对象是:
"carId" : "3C",
"_id" : ObjectId("51273329b64f07a40ef1c15e")
这是数据集(汽车):
"_id" : ObjectId("56223329b64f07a40ef1c15c"),
"username" : "john",
"email" : "john@john.com",
"accounts" : [
"_id" : ObjectId("56322329b61f07a40ef1c15d"),
"cars" : [
"carId" : "6A",
"_id" : ObjectId("56323329b64f07a40ef1c15e")
,
"carId" : "6B",
"_id" : ObjectId("56323329b64f07a40ef1c15e")
]
]
,
"_id" : ObjectId("56223125b64f07a40ef1c15c"),
"username" : "paul",
"email" : "paul@paul.com",
"accounts" : [
"_id" : ObjectId("5154729b61f07a40ef1c15d"),
"cars" : [
"carId" : "5B",
"_id" : ObjectId("56323329854f07a40ef1c15e")
]
,
"_id" : ObjectId("56322117b61f07a40ef1c15d"),
"cars" : [
"carId" : "6G",
"_id" : ObjectId("51212929b64f07a40ef1c15e")
,
"carId" : "3C",
"_id" : ObjectId("51273329b64f07a40ef1c15e")
,
"carId" : "4N",
"_id" : ObjectId("51241279b64f07a40ef1c15e")
]
]
请注意,我有两个嵌套数组,显然 MongoDb 在处理具有深度数组的投影时缺乏。 $ 运算符只能在投影中使用一次;离开时不知道如何完成这个简单的任务。
所以我想再次找到--only-- 具有“carId”的文档:“3C”并且只返回包含“carId”的直接obj:“3C”。但不是父对象。
任何帮助将不胜感激。可能使用直接的 MongoDb 或 Mongoose。猫鼬是首选。
作为参考,我已经涵盖了这些其他相关问题无法弄清楚。
Updating a deep record in MongoDb
How to Update Multiple Array Elements in mongodb
希望在未来,这个问题和你的解决方案能帮助到其他人。
【问题讨论】:
【参考方案1】:阿米尔,
您必须使用Aggregation Framework。您可以通过几个构建块构建一个处理流文档的管道:过滤、投影、分组、排序等。
在处理嵌套数组时,您必须使用$unwind
命令。您可以通过执行以下操作获得所需的内容。
db.cars.aggregate(
//De-normalized the nested array of accounts
"$unwind": "$accounts",
//De-normalized the nested array of cars
"$unwind": "$accounts.cars",
//match carId to 3C
"$match": "accounts.cars.carId" : "3C",
//Project the accoutns.cars object only
"$project" : "accounts.cars" : 1,
//Group and return only the car object
"$group":"_id":"$accounts.cars"
).pretty();
您可以通过 $unwind
使用聚合框架进行“数组过滤”。
您可以删除上述代码中聚合管道中每个命令底部的每一行,以观察管道行为。
【讨论】:
非常感谢,这听起来很棒;有没有办法用 Mongoose 达到同样的效果? 是的。您可以将它与猫鼬一起使用。我一拿到笔记本电脑就会添加到这个答案中。 刚刚尝试了这个聚合,它的工作原理就像一个魅力,除了一个小点。它返回: "_id" : ObjectId("56223125b64f07a40ef1c15c"), "accounts" : "cars" : "carId" : "3C", "_id" : ObjectId("51273329b64f07a40ef1c15e") 而不是预期对象:“汽车”:“carId”:“3C”,“_id”:ObjectId(“51273329b64f07a40ef1c15e”)。因此,从这一点开始,carId obj 可以通过 doc.accounts.cars 轻松访问,应该如何更改才能获得所需的结果。 ...?谢谢 再次非常感谢您。你是英雄。 -- 了解 Mongoose 语法也会很有帮助,因为我在代码中使用了 mongoose。谢谢 @AmirMog 我只是将答案更改为只返回一个对象。请让我知道它是否有效。【参考方案2】:这是一个没有聚合框架的示例。我认为没有一种方法可以纯粹通过查询来获得您正在寻找的单个嵌套对象,因此您必须做一些后期处理工作。像 Mongoose 这样的东西可能会提供一种方法来做到这一点,但我并不真正了解 Mongoose API 目前的样子。
var doc = db.cars.findOne("accounts.cars" : $elemMatch: "carId" : "3C", "accounts.cars.$": 1, _id: 0)
var car = doc.accounts[0].cars[0]
【讨论】:
在不知道包含“carId”的 obj 的索引的情况下是否可以工作:“3C”?我相信 var car = doc.accounts[0].cars[0] 不起作用,还是我遗漏了什么? 我使用您拥有的示例文档进行了测试。它确实有效,因为投影只会返回与查询匹配的第一个元素。您可能应该检查空值。 我刚刚修改了示例文档,以便 "carId" : "3C", "_id" : ObjectId("51273329b64f07a40ef1c15e") 不会位于数组中的索引 0 处。这还能用吗? 我刚刚检查了这个,投影实际上返回了“汽车”数组中的所有三个对象。它不会只返回一个。因此,尝试使用索引访问它无济于事。如何使投影返回只有一项为 "carId" : "3C", "_id" : ObjectId("51273329b64f07a40ef1c15e") 的“汽车”数组?谢谢 对不起。认为 $elemMatch 运算符可以在这里工作,但它似乎不适用于汽车数组,仅适用于帐户数组。如果不重组数据,聚合似乎是实现这一目标的方法。如果您将另一个答案标记为已接受的答案,则可能会删除它,因为我认为这种方法行不通。以上是关于MongoDb - 在嵌套数组中查找特定的 obj的主要内容,如果未能解决你的问题,请参考以下文章