假设我的收藏中有以下文件:
{
"_id":ObjectId("562e7c594c12942f08fe4192"),
"shapes":[
{
"shape":"square",
"color":"blue"
},
{
"shape":"circle",
"color":"red"
}
]
},
{
"_id":ObjectId("562e7c594c12942f08fe4193"),
"shapes":[
{
"shape":"square",
"color":"black"
},
{
"shape":"circle",
"color":"green"
}
]
}
做查询:
db.test.find({"shapes.color": "red"}, {"shapes.color": 1})
Or
db.test.find({shapes: {"$elemMatch": {color: "red"}}}, {"shapes.color": 1})
返回匹配的文档(文档1),但总是使用形状中的ALL数组项:
{ "shapes":
[
{"shape": "square", "color": "blue"},
{"shape": "circle", "color": "red"}
]
}
但是,我想只获得包含color=red的数组的文档(文档1):
{ "shapes":
[
{"shape": "circle", "color": "red"}
]
}
我该怎么做呢?
虽然这个问题是9.6年前问的,但这对很多人都有很大的帮助,我就是其中之一。感谢大家的提问、提示和回答。从这里的一个答案中…我发现下面的方法也可以用来投影父文档中的其他字段。这可能对某些人有帮助。
对于下面的文档,需要查明员工(emp #7839)是否将其休假历史设置为2020年。休假历史记录被实现为父雇员文档中的嵌入式文档。
db.employees.find( {"leave_history.calendar_year": 2020},
{leave_history: {$elemMatch: {calendar_year: 2020}},empno:true,ename:true}).pretty()
{
"_id" : ObjectId("5e907ad23997181dde06e8fc"),
"empno" : 7839,
"ename" : "KING",
"mgrno" : 0,
"hiredate" : "1990-05-09",
"sal" : 100000,
"deptno" : {
"_id" : ObjectId("5e9065f53997181dde06e8f8")
},
"username" : "none",
"password" : "none",
"is_admin" : "N",
"is_approver" : "Y",
"is_manager" : "Y",
"user_role" : "AP",
"admin_approval_received" : "Y",
"active" : "Y",
"created_date" : "2020-04-10",
"updated_date" : "2020-04-10",
"application_usage_log" : [
{
"logged_in_as" : "AP",
"log_in_date" : "2020-04-10"
},
{
"logged_in_as" : "EM",
"log_in_date" : ISODate("2020-04-16T07:28:11.959Z")
}
],
"leave_history" : [
{
"calendar_year" : 2020,
"pl_used" : 0,
"cl_used" : 0,
"sl_used" : 0
},
{
"calendar_year" : 2021,
"pl_used" : 0,
"cl_used" : 0,
"sl_used" : 0
}
]
}
虽然这个问题是9.6年前问的,但这对很多人都有很大的帮助,我就是其中之一。感谢大家的提问、提示和回答。从这里的一个答案中…我发现下面的方法也可以用来投影父文档中的其他字段。这可能对某些人有帮助。
对于下面的文档,需要查明员工(emp #7839)是否将其休假历史设置为2020年。休假历史记录被实现为父雇员文档中的嵌入式文档。
db.employees.find( {"leave_history.calendar_year": 2020},
{leave_history: {$elemMatch: {calendar_year: 2020}},empno:true,ename:true}).pretty()
{
"_id" : ObjectId("5e907ad23997181dde06e8fc"),
"empno" : 7839,
"ename" : "KING",
"mgrno" : 0,
"hiredate" : "1990-05-09",
"sal" : 100000,
"deptno" : {
"_id" : ObjectId("5e9065f53997181dde06e8f8")
},
"username" : "none",
"password" : "none",
"is_admin" : "N",
"is_approver" : "Y",
"is_manager" : "Y",
"user_role" : "AP",
"admin_approval_received" : "Y",
"active" : "Y",
"created_date" : "2020-04-10",
"updated_date" : "2020-04-10",
"application_usage_log" : [
{
"logged_in_as" : "AP",
"log_in_date" : "2020-04-10"
},
{
"logged_in_as" : "EM",
"log_in_date" : ISODate("2020-04-16T07:28:11.959Z")
}
],
"leave_history" : [
{
"calendar_year" : 2020,
"pl_used" : 0,
"cl_used" : 0,
"sl_used" : 0
},
{
"calendar_year" : 2021,
"pl_used" : 0,
"cl_used" : 0,
"sl_used" : 0
}
]
}
另一种有趣的方法是使用$编校,这是MongoDB 2.6的新聚合特性之一。如果您使用的是2.6,则不需要$unwind,如果您使用的是大型数组,$unwind可能会导致性能问题。
db.test.aggregate([
{ $match: {
shapes: { $elemMatch: {color: "red"} }
}},
{ $redact : {
$cond: {
if: { $or : [{ $eq: ["$color","red"] }, { $not : "$color" }]},
then: "$$DESCEND",
else: "$$PRUNE"
}
}}]);
$redact“根据存储在文档本身中的信息限制文档的内容”。所以它只会在文档内部运行。它基本上扫描你的文档从上到下,并检查它是否与你的if条件在$cond中匹配,如果有匹配,它将保留内容($$ descent)或删除($$PRUNE)。
在上面的例子中,第一个$match返回整个形状数组,$编校将其分解为预期的结果。
注意{$not:"$color"}是必要的,因为它也会扫描顶部的文档,如果$ react没有在顶部找到一个颜色字段,这将返回false,这可能会剥离整个文档,这是我们不想要的。