对不起,标题不好,但这是我要解决的问题:
我有几个集合,包括票证,字段和fieldOptions,看起来像这样:
门票:
{
_id: 1,
subject: "Lorem ipsum dolor sit amet, consectetur adipiscing elit",
fields: [
{
key: "part-number",
value: "abc123",
},
{
key: "price",
value: "10",
},
{
key: "officer",
value: "2",
},
]
}
字段:
[
{
_id: 1,
created: ISODate("2020-09-10T20:23:46.382Z"),
options: [],
updated: ISODate("2020-09-10T20:23:46.382Z"),
active: true,
displayOrder: 0,
key: "part-number",
label: "Part Number",
required: false,
type: "text",
},
{
_id: 2,
created: ISODate("2020-09-10T20:23:46.382Z"),
options: [],
updated: ISODate("2020-09-10T20:23:46.382Z"),
active: true,
displayOrder: 1,
key: "price",
label: "Price",
required: false,
type: "text",
},
{
_id: 3,
created: ISODate("2020-09-10T20:23:46.382Z"),
options: [1, 2, 3, 4],
updated: ISODate("2020-09-10T20:23:46.382Z"),
active: true,
displayOrder: 2,
key: "officer",
label: "Officer",
required: false,
type: "select",
},
// THIS WAS ADDED AFTER THE 'TICKET' DOC WAS CREATED, SO IT'S NOT LISTED UNDER 'FIELDS' IN THERE
{
_id: 4,
created: ISODate("2020-09-10T20:23:46.382Z"),
options: [],
updated: ISODate("2020-09-10T20:23:46.382Z"),
active: true,
displayOrder: 1,
key: "notes",
label: "Notes",
required: false,
type: "text",
},
]
字段选项:
[
{
_id: 1,
created: ISODate("2020-09-10T20:23:46.382Z"),
updated: ISODate("2020-09-10T20:23:46.382Z"),
active: true,
key: "none",
label: "None",
displayOrder: 0,
legacy: false,
},
{
_id: 2,
created: ISODate("2020-09-10T20:23:46.382Z"),
updated: ISODate("2020-09-10T20:23:46.382Z"),
active: true,
key: "picard",
label: "Picard",
displayOrder: 1,
legacy: false,
},
{
_id: 3,
created: ISODate("2020-09-10T20:23:46.382Z"),
updated: ISODate("2020-09-10T20:23:46.382Z"),
active: true,
key: "riker",
label: "Riker",
displayOrder: 2,
legacy: false,
},
{
_id: 4,
created: ISODate("2020-09-10T20:23:46.382Z"),
updated: ISODate("2020-09-10T20:23:46.382Z"),
active: true,
key: "data",
label: "Data",
displayOrder: 3,
legacy: false,
},
{
_id: 5,
created: ISODate("2020-09-10T20:23:46.382Z"),
updated: ISODate("2020-09-10T20:23:46.382Z"),
active: true,
key: "red-shirt",
label: "Red Shirt",
displayOrder: 4,
legacy: true,
},
]
在我的聚合管道中,我有以下内容:
[
{ $match: {_id: 2} },
{ $unwind: { path: "$fields", "preserveNullAndEmptyArrays": true } },
{
"$lookup": {
"from": "fields",
"let": { "key": "$fields.key" },
"as": "fields.def",
"pipeline": [
{ "$match": { "$expr": { "$eq": ["$key", "$$key"] } } },
{
"$lookup": {
"from": "fieldoptions",
"let": { "options": "$options" },
"pipeline": [
{ "$match": { "$expr": { "$in": ["$_id", "$$options"] } } },
],
"as": "options"
}
}
]
}
},
{ $unwind: { path: "$fields.def", "preserveNullAndEmptyArrays": true } },
{
$group: {
_id: "$_id",
fields: { $push: "$$ROOT.fields" },
root: { $mergeObjects: "$$ROOT" },
}
},
{
$replaceRoot: {
newRoot: {
$mergeObjects: ["$root", "$$ROOT"]
}
}
},
{
$unset: "root"
},
{ $project: { fields: '$fields'}} // this is to remove other junk for testing
]
这带来了以下(几乎正确的)结果:
{
"_id" : 2,
"fields" : [
{
"key" : "part-number",
"value" : "abc123",
"def" : {
"_id" : 1,
"created" : ISODate("2020-09-10T20:23:46.382Z"),
"options" : [],
"updated" : ISODate("2020-09-10T20:23:46.382Z"),
"active" : true,
"displayOrder" : 0,
"key" : "part-number",
"label" : "Part Number",
"required" : false,
"type" : "text",
"__v" : 0
}
},
{
"key" : "price",
"value" : "10",
"def" : {
"_id" : 2,
"created" : ISODate("2020-09-10T20:23:46.382Z"),
"options" : [],
"updated" : ISODate("2020-09-10T20:23:46.382Z"),
"active" : true,
"displayOrder" : 1,
"key" : "price",
"label" : "Price",
"required" : false,
"type" : "text",
"__v" : 0
}
},
{
"key" : "officer",
"value" : "2",
"def" : {
"_id" : 3,
"created" : ISODate("2020-09-10T20:23:46.382Z"),
"options" : [
{
"_id" : 1,
"created" : ISODate("2020-09-10T20:23:46.382Z"),
"updated" : ISODate("2020-09-10T20:23:46.382Z"),
"active" : true,
"key" : "none",
"label" : "None",
"displayOrder" : 0,
"legacy" : false,
"__v" : 0
},
{
"_id" : 2,
"created" : ISODate("2020-09-10T20:23:46.382Z"),
"updated" : ISODate("2020-09-10T20:23:46.382Z"),
"active" : true,
"key" : "picard",
"label" : "Picard",
"displayOrder" : 1,
"legacy" : false,
"__v" : 0
},
{
"_id" : 3,
"created" : ISODate("2020-09-10T20:23:46.382Z"),
"updated" : ISODate("2020-09-10T20:23:46.382Z"),
"active" : true,
"key" : "riker",
"label" : "Riker",
"displayOrder" : 2,
"legacy" : false,
"__v" : 0
},
{
"_id" : 4,
"created" : ISODate("2020-09-10T20:23:46.382Z"),
"updated" : ISODate("2020-09-10T20:23:46.382Z"),
"active" : true,
"key" : "data",
"label" : "Data",
"displayOrder" : 3,
"legacy" : false,
"__v" : 0
}
],
"updated" : ISODate("2020-09-10T20:23:46.382Z"),
"active" : true,
"displayOrder" : 2,
"key" : "officer",
"label" : "Officer",
"required" : false,
"type" : "select",
"__v" : 0
}
}
]
}
我的问题是,如果我向'fields'集合中添加某些内容(我们将其称为属性'foo'),则现有的票证对象没有'foo'引用,因此它不会显示在票证对象中,我想以某种方式(在聚合框架中)获取当前字段的列表,并为每个字段查找对应的值(如果存在),否则返回一个空值,如下所示:
新票务结果:
{
_id: 2,
fields: [
... //existing fields
{
key: "foo", // <-- new fields / fields not listed on the ticket
value: null,
def: {
_id: 1,
created: ISODate("2020-09-10T20:23:46.382Z"),
options: [],
updated: ISODate("2020-09-10T20:23:46.382Z"),
active: true,
displayOrder: 0,
key: "foo",
label: "Foo",
required: false,
type: "text",
__v: 0,
},
},
],
}
如何实现?另外,有没有比我现有的方法更好的方法了?我是聚合技术的新手,还在尝试。
答案 0 :(得分:1)
合并这两个字段是一个非常漫长的过程,您可以按照以下步骤操作,
$match
您的情况$addFields
在key
数组中添加字段keys
的数组$facet
生成2个单独的数组,一个用于匹配的字段,第二个用于不匹配的数组
fields
中创建匹配字段的数组,在let和match keys
查询和查找中使用$in
集合传递fieldoptions
数组,
$project
使用$map
和$reduce
获取具有当前根键和值的组合对象other_fields
中创建不匹配字段的数组,在let和match keys
和$not
中传递$in
数组意味着不包含fieldoptions
集合并进行查找
$project
使用$map
和$mergeObjects
获取具有当前根键和值的组合对象$project
使用fields
合并$concatArrays
数组中的两个数组$unwind
解构fields
数组$replaceWith
fields
对象替换为根$unwind
解构fields
数组$group
按票证ID并构造fields
数组db.ticket.aggregate([
{ $match: { _id: 1 } },
{ $addFields: { keys: { $map: { input: "$fields", in: "$$this.key" } } } },
{
$facet: {
fields: [
{
$lookup: {
from: "fields",
let: { key: "$keys" },
as: "_fields",
pipeline: [
{ $match: { $expr: { $in: ["$key", "$$key"] } } },
{
$lookup: {
from: "fieldoptions",
localField: "options",
foreignField: "_id",
as: "options"
}
}
]
}
},
{
$project: {
fields: {
$map: {
input: "$fields",
as: "f",
in: {
$mergeObjects: [
"$$f",
{
def: {
$reduce: {
input: "$_fields",
initialValue: {},
in: {
$cond: [{ $eq: ["$$f.key", "$$this.key"] }, "$$this", "$$value"]
}
}
}
}
]
}
}
}
}
}
],
other_fields: [
{
$lookup: {
from: "fields",
let: { key: "$keys" },
as: "_fields",
pipeline: [
{ $match: { $expr: { $not: { $in: ["$key", "$$key"] } } } },
{
$lookup: {
from: "fieldoptions",
localField: "options",
foreignField: "_id",
as: "options"
}
}
]
}
},
{
$project: {
fields: {
$map: {
input: "$_fields",
as: "f",
in: {
$mergeObjects: [
{ def: "$$f" },
{ key: "$$f.key", value: null }
]
}
}
}
}
}
]
}
},
{ $project: { fields: { $concatArrays: ["$fields", "$other_fields"] } } },
{ $unwind: "$fields" },
{ $replaceWith: "$fields" },
{
$unwind: {
path: "$fields",
preserveNullAndEmptyArrays: true
}
},
{
$group: {
_id: "$_id",
fields: { $push: "$$ROOT.fields" }
}
}
])
您正在查询的查询,这是该查询Playground的优化版本