我有这样的外部对象:
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"
}
答案 0 :(得分:1)
你有点走在正确的轨道上,但是你在错误的地方使用$let
。因此,一般的想法是应用$let
“围绕”表达式来评估而不是“内部”它们。
另外,在将作为输入值输入管道之前,您确实应该使对象与“数组”匹配。运算符使用“数组”,并且不能很好地处理由变量名称查找“对象”。
所以这可能是最短的,因为$indexOfArray
和$arrayElemAt
都可用,以便匹配和提取值:{/ p>
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
,$arrayElemAt
从这些组合语句中提取“第一个匹配项”:< / p>
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
的任何用法,因为我们没有直接针对除"input"
到$filter
以外的任何内容提供变量。
无论应用哪个,都会使用输入obj
中提供的索引位置(作为数组强制为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"
}