将数组索引匹配到提供的对象variables
我有这样的外部对象:
var obj = { a: 2, b: 0, c: 1 }
此外,我有与引用obj字段“ref”的集合。 obj对象中的值被视为集合中的数组字段的索引。
{ ref: "a", array: ["xyz", "abc", "def"] } { ref: "b", array: ["sde", "xda", "era"] } { ref: "c", array: ["wwe", "aea", "fre"] }
我想聚集收集只有一个取决于在obj中指定的索引值的数组。
.aggregate([ { $project: { code: $arrayElemAt: ["$array", { $let: { vars: { obj: obj }, in: "$$obj.$ref" //Field path used as variable field name of object }}] } }])
但是我得到以下错误:
MongoError: FieldPath field names may not start with '$'.
这是相关的我认为以下的东西: in: "$$obj.$ref"
所需的聚合结果是:
{ ref: "a", code: "def" } { ref: "b", code: "sde" } { ref: "c", code: "aea" }
你有点走错了路,但是你在错误的地方使用$let
。 所以总的想法是应用$let
“围绕”expression式来评估,而不是“内部”。
另外,你真的应该把这个对象作为一个input值与一个“数组”进行匹配。 操作符使用“数组”,而不处理通过variables名称很好地查找“对象”。
所以这可能是最短的$indexOfArray
和$arrayElemAt
,两者都可用来匹配和提取值:
var obj = { a: 2, b: 0, c: 1 }; var input = Object.keys(obj).map(k => ({ k: k, v: obj[k] })); // Outputs as // [{ "k" : "a", "v" : 2 }, { "k" : "b", "v" : 0 }, { "k" : "c", "v" : 1 }] db.collection.aggregate([ { "$addFields": { "array": { "$let": { "vars": { "obj": input }, "in": { "$arrayElemAt": [ "$array", { "$arrayElemAt": [ "$$obj.v", { "$indexOfArray": [ "$$obj.k", "$ref" ] } ]} ] } } } }} ])
如果你真的有MongoDB 3.4.4或更高版本,那么你可以“内部”应用$objectToArray
,但是它并没有真正添加任何值(它真的只是炫耀):
var obj = { a: 2, b: 0, c: 1 }; //var input = Object.keys(obj).map(k => ({ k: k, v: obj[k] })); db.collection.aggregate([ { "$addFields": { "array": { "$let": { "vars": { "obj": { "$objectToArray": obj } }, "in": { "$arrayElemAt": [ "$array", { "$arrayElemAt": [ "$$obj.v", { "$indexOfArray": [ "$$obj.k", "$ref" ] } ]} ] } } } }} ])
如果您的MongoDB不支持$indexOfArray
,那么您总是可以应用$map
和$filter
来获取这些合并语句中的“first match”: $arrayElemAt
var obj = { a: 2, b: 0, c: 1 }; var input = Object.keys(obj).map(k => ({ k: k, v: obj[k] })); db.collection.aggregate([ { "$addFields": { "array": { "$arrayElemAt": [ "$array", { "$arrayElemAt": [ { "$map": { "input": { "$filter": { "input": input, "cond": { "$eq": [ "$$this.k", "$ref" ] } } }, "in": "$$this.v" }}, 0 ]} ] } }} ])
这也消除了$let
任何用法,因为我们不直接针对提供给variables的"input"
到$filter
以外的任何东西。
无论哪个应用,都来自相同的输出使用从inputobj
提供的索引位置(强制input
为数组),并返回该数组条目:
/* 1 */ { "_id" : ObjectId("59a76d6fad465e105d9136dc"), "ref" : "a", "array" : "def" } /* 2 */ { "_id" : ObjectId("59a76d6fad465e105d9136dd"), "ref" : "b", "array" : "sde" } /* 3 */ { "_id" : ObjectId("59a76d6fad465e105d9136de"), "ref" : "c", "array" : "aea" }