我有一个类似于以下结构的mongo文档:
{
id: '111eef8b94d3e91f4c7d22a37deb4aad',
description: 'Secret Project',
title: 'secret project',
students: [
{ _id: '123', name: 'Alex', primary_subject: 'Math', address: 'xxxxx', dob: '1989-10-10', gender: 'F', nationality: 'German' },
{ _id: '124', name: 'Emanuel', primary_subject: 'Physics', address: 'yyyyyy', dob: '1988-05-07', gender: 'M', nationality: 'French' },
{ _id: '242', name: 'Mike', primary_subject: 'Chemistry', address: 'zzzz', dob: '1990-02-02', gender: 'M', nationality: 'English' }
]
}
我需要获取特定属性。例如,只想获取名称,primary_subject,国籍属性。 使用下面的mongo查询,我可以获取所有属性。
db.student_projects.aggregate({
$project: {
"students": {
$filter: {
input: "$students",
as: "st",
cond: {
$eq: [ "$$st._id", "242" ]
}
},
}
}
},
{ $unwind: { path: "$students", preserveNullAndEmptyArrays: false } }
).pretty();
以上查询将获取匹配学生的所有属性。但就我而言,我只需要3个属性。
答案 0 :(得分:0)
使用$map
重塑输出数组的形状:
db.student_projects.aggregate({
$project: {
"students": {
$map: {
input: {
$filter: {
input: "$students",
as: "st",
cond: {
$eq: [ "$$st._id", "242" ]
}
}
},
in: {
name: "$$this.name",
primary_subject: "$$this.primary_subject",
nationality: "$$this.nationality"
}
}
}
}
},
{ $unwind: { path: "$students", preserveNullAndEmptyArrays: false } }
).pretty();
就像$map
一样,“重塑” 数组就像其他语言一样。
如果您想获得比“排除”更长的“包含”字段列表的“花哨”,那么从更高版本的MongoDB 3.6及更高版本中可以找到一些现代的运算符,可以在这里提供帮助:
db.student_projects.aggregate({
$project: {
"students": {
$map: {
input: {
$filter: {
input: "$students",
as: "st",
cond: {
$eq: [ "$$st._id", "242" ]
}
}
},
in: {
$arrayToObject: {
$filter: {
input: { $objectToArray: "$$this" },
cond: {
"$not": {
"$in": [ "$$this.k", [ "_id", "address", "dob" ] ]
}
}
}
}
}
}
}
}
},
{ $unwind: "$students" }
).pretty();
$objectToArray
转换为k
和v
的“键/值”对,代表对象键和值。从这个“数组”中,您可以$filter
在k
值上为不需要的结果。 $in
允许与“列表”进行比较,而$not
则将比较值取反。
最后,您可以通过$arrayToObject
将“数组”转换回对象形式。
当然,您总是可以在$project
之后简单地$unwind
:
db.student_projects.aggregate({
$project: {
"students": {
$filter: {
input: "$students",
as: "st",
cond: {
$eq: [ "$$st._id", "242" ]
}
},
}
}
},
{ $unwind: "$students" },
{ $project: {
"students": {
"name": "$students.name",
"primary_subject": "$students.primary_subject",
"nationality": "$students.nationality"
}
}
).pretty();
如果不想使用"students"
键,只需将其删除:
{ $project: {
"name": "$students.name",
"primary_subject": "$students.primary_subject",
"nationality": "$students.nationality"
}
或使用原始$map
版本的$replaceRoot
:
db.student_projects.aggregate({
$project: {
"students": {
$map: {
input: {
$filter: {
input: "$students",
as: "st",
cond: {
$eq: [ "$$st._id", "242" ]
}
}
},
in: {
name: "$$this.name",
primary_subject: "$$this.primary_subject",
nationality: "$$this.nationality"
}
}
}
}
},
{ $unwind: "$students" },
{ $replaceRoot: { newRoot: "$students" } }
).pretty();
但是,为此,您也可以在$match
之后执行$unwind
,而不是甚至使用$filter
。不过,通常就地使用数组更有效,而且很多时候根本不需要$unwind
,因此习惯习惯于操纵数组的方法是一种很好的做法。
当然,如果使用$replaceRoot
或类似的结果确实是您想要的结果,那么最好根本不使用数组中的嵌入式文档。如果您打算使用的访问模式通常在大多数时候“独立”地使用那些嵌入文档,那么您应该考虑将它们保留在自己的集合中。这样可以避免“聚合开销”,并且是返回数据的简单查询和投影。
NB
$unwind
运算符“默认”为preserveNullAndEmptyArrays: false
。因此,原始格式不需要指定的格式,也不需要path
键。除非您专门打算保留那些空值和空值,否则用这种方式编写的时间会较短。