仅检索 MongoDB 集合中对象数组中的查询元素
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3985214/
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
Retrieve only the queried element in an object array in MongoDB collection
提问by Sebtm
Suppose you have the following documents in my collection:
假设您在我的收藏中有以下文档:
{
"_id":ObjectId("562e7c594c12942f08fe4192"),
"shapes":[
{
"shape":"square",
"color":"blue"
},
{
"shape":"circle",
"color":"red"
}
]
},
{
"_id":ObjectId("562e7c594c12942f08fe4193"),
"shapes":[
{
"shape":"square",
"color":"black"
},
{
"shape":"circle",
"color":"green"
}
]
}
Do query:
做查询:
db.test.find({"shapes.color": "red"}, {"shapes.color": 1})
Or
或者
db.test.find({shapes: {"$elemMatch": {color: "red"}}}, {"shapes.color": 1})
Returns matched document (Document 1), but always with ALL array items in shapes
:
返回匹配的文档(Document 1),但始终包含 ALL 数组项shapes
:
{ "shapes":
[
{"shape": "square", "color": "blue"},
{"shape": "circle", "color": "red"}
]
}
However, I'd like to get the document (Document 1)only with the array that contains color=red
:
但是,我只想使用包含以下内容的数组获取文档(文档 1)color=red
:
{ "shapes":
[
{"shape": "circle", "color": "red"}
]
}
How can I do this?
我怎样才能做到这一点?
回答by JohnnyHK
MongoDB 2.2's new $elemMatch
projection operator provides another way to alter the returned document to contain only the firstmatched shapes
element:
MongoDB 2.2 的新$elemMatch
投影运算符提供了另一种方法来更改返回的文档以仅包含第一个匹配的shapes
元素:
db.test.find(
{"shapes.color": "red"},
{_id: 0, shapes: {$elemMatch: {color: "red"}}});
Returns:
返回:
{"shapes" : [{"shape": "circle", "color": "red"}]}
In 2.2 you can also do this using the $ projection operator
, where the $
in a projection object field name represents the index of the field's first matching array element from the query. The following returns the same results as above:
在 2.2 中,您还可以使用 来执行此操作$ projection operator
,其中$
投影对象中的字段名称表示该字段在查询中的第一个匹配数组元素的索引。以下返回与上述相同的结果:
db.test.find({"shapes.color": "red"}, {_id: 0, 'shapes.$': 1});
MongoDB 3.2 Update
MongoDB 3.2 更新
Starting with the 3.2 release, you can use the new $filter
aggregation operator to filter an array during projection, which has the benefit of including allmatches, instead of just the first one.
从 3.2 版本开始,您可以使用新的$filter
聚合运算符在投影期间过滤数组,这样的好处是可以包含所有匹配项,而不仅仅是第一个匹配项。
db.test.aggregate([
// Get just the docs that contain a shapes element where color is 'red'
{$match: {'shapes.color': 'red'}},
{$project: {
shapes: {$filter: {
input: '$shapes',
as: 'shape',
cond: {$eq: ['$$shape.color', 'red']}
}},
_id: 0
}}
])
Results:
结果:
[
{
"shapes" : [
{
"shape" : "circle",
"color" : "red"
}
]
}
]
回答by Stennie
The new Aggregation Frameworkin MongoDB 2.2+ provides an alternative to Map/Reduce. The $unwind
operator can be used to separate your shapes
array into a stream of documents that can be matched:
MongoDB 2.2+ 中的新聚合框架提供了 Map/Reduce 的替代方案。该$unwind
运算符可用于将您的shapes
数组分隔为可以匹配的文档流:
db.test.aggregate(
// Start with a $match pipeline which can take advantage of an index and limit documents processed
{ $match : {
"shapes.color": "red"
}},
{ $unwind : "$shapes" },
{ $match : {
"shapes.color": "red"
}}
)
Results in:
结果是:
{
"result" : [
{
"_id" : ObjectId("504425059b7c9fa7ec92beec"),
"shapes" : {
"shape" : "circle",
"color" : "red"
}
}
],
"ok" : 1
}
回答by Niels van der Rest
Caution:This answer provides a solution that was relevant at that time, before the new features of MongoDB 2.2 and up were introduced. See the other answers if you are using a more recent version of MongoDB.
注意:这个答案提供了一个当时相关的解决方案,在引入 MongoDB 2.2 及更高版本的新功能之前。如果您使用的是更新版本的 MongoDB,请参阅其他答案。
The field selector parameter is limited to complete properties. It cannot be used to select part of an array, only the entire array. I tried using the $ positional operator, but that didn't work.
字段选择器参数仅限于完整的属性。它不能用于选择数组的一部分,只能用于选择整个数组。我尝试使用$ positional operator,但这不起作用。
The easiest way is to just filter the shapes in the client.
最简单的方法是只过滤客户端中的形状。
If you really needthe correct output directly from MongoDB, you can use a map-reduceto filter the shapes.
如果你真的需要直接从 MongoDB 中得到正确的输出,你可以使用 map-reduce来过滤形状。
function map() {
filteredShapes = [];
this.shapes.forEach(function (s) {
if (s.color === "red") {
filteredShapes.push(s);
}
});
emit(this._id, { shapes: filteredShapes });
}
function reduce(key, values) {
return values[0];
}
res = db.test.mapReduce(map, reduce, { query: { "shapes.color": "red" } })
db[res.result].find()
回答by anvarik
Another interesing way is to use $redact, which is one of the new aggregation features of MongoDB 2.6. If you are using 2.6, you don't need an $unwind which might cause you performance problems if you have large arrays.
另一种有趣的方法是使用$redact,这是MongoDB 2.6的新聚合特性之一。如果您使用的是 2.6,则不需要 $unwind,如果您有大型数组,它可能会导致性能问题。
db.test.aggregate([
{ $match: {
shapes: { $elemMatch: {color: "red"} }
}},
{ $redact : {
$cond: {
if: { $or : [{ $eq: ["$color","red"] }, { $not : "$color" }]},
then: "$$DESCEND",
else: "$$PRUNE"
}
}}]);
$redact
"restricts the contents of the documents based on information stored in the documents themselves". So it will run only inside of the document. It basically scans your document top to the bottom, and checks if it matches with your if
condition which is in $cond
, if there is match it will either keep the content($$DESCEND
) or remove($$PRUNE
).
$redact
“根据文档本身存储的信息限制文档的内容”。所以它只会在文档内部运行。它基本上从上到下扫描您的文档,并检查它是否与您的if
条件匹配$cond
,如果匹配,它将保留内容($$DESCEND
)或删除($$PRUNE
)。
In the example above, first $match
returns the whole shapes
array, and $redact strips it down to the expected result.
在上面的示例中,首先$match
返回整个shapes
数组,然后 $redact 将其剥离为预期结果。
Note that {$not:"$color"}
is necessary, because it will scan the top document as well, and if $redact
does not find a color
field on the top level this will return false
that might strip the whole document which we don't want.
请注意,这{$not:"$color"}
是必要的,因为它也会扫描顶层文档,如果在顶层$redact
没有找到color
字段,这将返回false
可能会删除我们不想要的整个文档。
回答by Narendran
Better you can query in matching array element using $slice
is it helpful to returning the significant object in an array.
您可以更好地查询匹配的数组元素,使用$slice
是否有助于返回数组中的重要对象。
db.test.find({"shapes.color" : "blue"}, {"shapes.$" : 1})
$slice
is helpful when you know the index of the element, but sometimes you want
whichever array element matched your criteria. You can return the matching element
with the $
operator.
$slice
当您知道元素的索引时很有帮助,但有时您想要任何与您的条件匹配的数组元素。您可以使用$
运算符返回匹配的元素。
回答by Viral Patel
db.getCollection('aj').find({"shapes.color":"red"},{"shapes.$":1})
OUTPUTS
输出
{
"shapes" : [
{
"shape" : "circle",
"color" : "red"
}
]
}
回答by Vicky
The syntax for find in mongodb is
在 mongodb 中 find 的语法是
db.<collection name>.find(query, projection);
and the second query that you have written, that is
以及您编写的第二个查询,即
db.test.find(
{shapes: {"$elemMatch": {color: "red"}}},
{"shapes.color":1})
in this you have used the $elemMatch
operator in query part, whereas if you use this operator in the projection part then you will get the desired result. You can write down your query as
在这里,您$elemMatch
在查询部分使用了运算符,而如果您在投影部分使用此运算符,那么您将获得所需的结果。您可以将查询写为
db.users.find(
{"shapes.color":"red"},
{_id:0, shapes: {$elemMatch : {color: "red"}}})
This will give you the desired result.
这会给你想要的结果。
回答by Eddy
Thanks to JohnnyHK.
感谢JohnnyHK。
Here I just want to add some more complex usage.
这里我只想添加一些更复杂的用法。
// Document
{
"_id" : 1
"shapes" : [
{"shape" : "square", "color" : "red"},
{"shape" : "circle", "color" : "green"}
]
}
{
"_id" : 2
"shapes" : [
{"shape" : "square", "color" : "red"},
{"shape" : "circle", "color" : "green"}
]
}
// The Query
db.contents.find({
"_id" : ObjectId(1),
"shapes.color":"red"
},{
"_id": 0,
"shapes" :{
"$elemMatch":{
"color" : "red"
}
}
})
//And the Result
{"shapes":[
{
"shape" : "square",
"color" : "red"
}
]}
回答by Vaibhav Patil
You just need to run query
你只需要运行查询
db.test.find(
{"shapes.color": "red"},
{shapes: {$elemMatch: {color: "red"}}});
output of this query is
此查询的输出是
{
"_id" : ObjectId("562e7c594c12942f08fe4192"),
"shapes" : [
{"shape" : "circle", "color" : "red"}
]
}
as you expected it'll gives the exact field from array that matches color:'red'.
正如您所料,它会从数组中提供与颜色匹配的确切字段:'red'。
回答by shakthydoss
along with $project it will be more appropriate other wise matching elements will be clubbed together with other elements in document.
与 $project 一起使用将更合适,其他明智的匹配元素将与文档中的其他元素一起使用。
db.test.aggregate(
{ "$unwind" : "$shapes" },
{ "$match" : {
"shapes.color": "red"
}},
{"$project":{
"_id":1,
"item":1
}}
)