Seb*_*btm 356 projection mongodb mongodb-query aggregation-framework
假设我的收藏中有以下文件:
{
"_id":ObjectId("562e7c594c12942f08fe4192"),
"shapes":[
{
"shape":"square",
"color":"blue"
},
{
"shape":"circle",
"color":"red"
}
]
},
{
"_id":ObjectId("562e7c594c12942f08fe4193"),
"shapes":[
{
"shape":"square",
"color":"black"
},
{
"shape":"circle",
"color":"green"
}
]
}
Run Code Online (Sandbox Code Playgroud)
查询:
db.test.find({"shapes.color": "red"}, {"shapes.color": 1})
Run Code Online (Sandbox Code Playgroud)
要么
db.test.find({shapes: {"$elemMatch": {color: "red"}}}, {"shapes.color": 1})
Run Code Online (Sandbox Code Playgroud)
返回匹配的文档(文档1),但始终包含所有数组项shapes
:
{ "shapes":
[
{"shape": "square", "color": "blue"},
{"shape": "circle", "color": "red"}
]
}
Run Code Online (Sandbox Code Playgroud)
但是,我想仅使用包含以下内容的数组来获取文档(文档1)color=red
:
{ "shapes":
[
{"shape": "circle", "color": "red"}
]
}
Run Code Online (Sandbox Code Playgroud)
我怎样才能做到这一点?
Joh*_*yHK 386
MongoDB 2.2的新$elemMatch
投影操作符提供了另一种方法来更改返回的文档以仅包含第一个匹配的shapes
元素:
db.test.find(
{"shapes.color": "red"},
{_id: 0, shapes: {$elemMatch: {color: "red"}}});
Run Code Online (Sandbox Code Playgroud)
返回:
{"shapes" : [{"shape": "circle", "color": "red"}]}
Run Code Online (Sandbox Code Playgroud)
在2.2中,您也可以使用$ projection operator
,其中$
投影对象字段名称表示字段中查询的第一个匹配数组元素的索引.以下返回与上面相同的结果:
db.test.find({"shapes.color": "red"}, {_id: 0, 'shapes.$': 1});
Run Code Online (Sandbox Code Playgroud)
MongoDB 3.2更新
从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
}}
])
Run Code Online (Sandbox Code Playgroud)
结果:
[
{
"shapes" : [
{
"shape" : "circle",
"color" : "red"
}
]
}
]
Run Code Online (Sandbox Code Playgroud)
Ste*_*nie 95
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"
}}
)
Run Code Online (Sandbox Code Playgroud)
结果是:
{
"result" : [
{
"_id" : ObjectId("504425059b7c9fa7ec92beec"),
"shapes" : {
"shape" : "circle",
"color" : "red"
}
}
],
"ok" : 1
}
Run Code Online (Sandbox Code Playgroud)
Nie*_*est 29
注意:这个答案提供了一个解决方案,这是有关在那个时候,引入了之前的MongoDB 2.2的新功能和最多.如果您使用的是更新版本的MongoDB,请参阅其他答案.
字段选择器参数仅限于完整属性.它不能用于选择数组的一部分,只能用于整个数组.我尝试使用$ position运算符,但这不起作用.
最简单的方法是只过滤客户端中的形状.
如果您确实需要直接从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()
Run Code Online (Sandbox Code Playgroud)
anv*_*rik 28
另一种有趣的方法是使用$ 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"
}
}}]);
Run Code Online (Sandbox Code Playgroud)
$redact
"根据文件本身存储的信息限制文件的内容".所以它只会在文档内部运行.它基本上扫描你的文档顶部到底部,并检查它是否与你的if
条件匹配$cond
,如果有匹配,它将保留content($$DESCEND
)或remove($$PRUNE
).
在上面的示例中,首先$match
返回整个shapes
数组,$ redact将其删除到预期结果.
请注意,这{$not:"$color"}
是必要的,因为它也将扫描顶层文档,如果在顶层$redact
找不到color
字段,则返回false
可能会删除我们不想要的整个文档.
小智 21
更好的是你可以使用匹配的数组元素进行查询$slice
是否有助于返回数组中的重要对象.
db.test.find({"shapes.color" : "blue"}, {"shapes.$" : 1})
Run Code Online (Sandbox Code Playgroud)
$slice
当你知道元素的索引时很有用,但有时候你想要哪个数组元素符合你的标准.您可以使用$
运算符返回匹配元素.
Vir*_*tel 16
db.getCollection('aj').find({"shapes.color":"red"},{"shapes.$":1})
Run Code Online (Sandbox Code Playgroud)
产出
{
"shapes" : [
{
"shape" : "circle",
"color" : "red"
}
]
}
Run Code Online (Sandbox Code Playgroud)
Vic*_*cky 11
在mongodb中查找的语法是
db.<collection name>.find(query, projection);
Run Code Online (Sandbox Code Playgroud)
和你写的第二个查询,即
db.test.find(
{shapes: {"$elemMatch": {color: "red"}}},
{"shapes.color":1})
Run Code Online (Sandbox Code Playgroud)
在这里你已经$elemMatch
在查询部分使用了运算符,而如果你在投影部分使用这个运算符,那么你将得到所需的结果.您可以将查询写下来
db.users.find(
{"shapes.color":"red"},
{_id:0, shapes: {$elemMatch : {color: "red"}}})
Run Code Online (Sandbox Code Playgroud)
这将为您提供所需的结果.
在这里,我只想添加一些更复杂的用法.
// 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"
}
]}
Run Code Online (Sandbox Code Playgroud)
您只需要运行查询
db.test.find(
{"shapes.color": "red"},
{shapes: {$elemMatch: {color: "red"}}});
Run Code Online (Sandbox Code Playgroud)
此查询的输出是
{
"_id" : ObjectId("562e7c594c12942f08fe4192"),
"shapes" : [
{"shape" : "circle", "color" : "red"}
]
}
Run Code Online (Sandbox Code Playgroud)
如你所料,它将从匹配颜色的数组中提供确切的字段:'red'.
除此之外, $project
其他明智的匹配元素将与文档中的其他元素组合在一起会更合适。
db.test.aggregate(
{ "$unwind" : "$shapes" },
{ "$match" : { "shapes.color": "red" } },
{
"$project": {
"_id":1,
"item":1
}
}
)
Run Code Online (Sandbox Code Playgroud)
同样你可以找到多个
db.getCollection('localData').aggregate([
// Get just the docs that contain a shapes element where color is 'red'
{$match: {'shapes.color': {$in : ['red','yellow'] } }},
{$project: {
shapes: {$filter: {
input: '$shapes',
as: 'shape',
cond: {$in: ['$$shape.color', ['red', 'yellow']]}
}}
}}
])
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
264629 次 |
最近记录: |