MongoDB聚合操作:展开数组和非数组

3

我正在尝试使用$unwind编写聚合查询,无论元素是否为数组。 我知道$unwind无法处理非数组元素,但我想知道是否有一种方法使其起作用,例如将此元素转换为数组。

我的集合如下:

{

    {"x" : 1, "y" : {"c" : 2, "i" : 3}},
    {"x" : 1, "y" : [{"c" : 4, "i" : 5}, {"c" : 6, "i" : 7}]}

}

在使用$unwind之前,我认为需要像这样:

{

  {"x" : 1, "y" : [{"c" : 2, "i" : 3}]},
  {"x" : 1, "y" : [{"c" : 4, "i" : 5}, {"c" : 6, "i" : 7}]}
}

到目前为止在$project阶段,我可以检查元素是否是数组,但我不知道如何使用这个信息来创建或不创建一个数组。我知道我可以使用$push来创建一个数组,但如何保持未更改的数组元素并只推送没有数组元素?
我尝试了这个:
{$group : {"_id" : "$x", "myArray" : {$push : {$cond : {if : "$isArray", then : "$y", else : ["$y"]}}}}}

使用上述代码,我尝试将所有元素放在同一级别,但未成功,因为["$y"]返回的确切是(["$y"]),没有评估,只是一个包含字符串的数组。
我不想$unwind一个空数组,我想将非数组元素转换为数组元素,以便我可以$unwind。
任何帮助都将不胜感激。

我不理解你关于将样本更改为相同内容的评论。第一个样本包含“y”的数组和非数组元素,而第二个样本是我需要的,其中所有“y”元素都是数组。关于可能的重复项,我认为这不是我的情况,因为我没有空数组。我有一个非数组元素,我想将其转换为数组,以便我可以$unwind。 - Raul Martinez
我同意这不是一个好主意,但我并没有编写那个集合,而且现在更改它也不可行。 - Raul Martinez
1个回答

5
这基本上可以通过$cond$ifNull的帮助来实现你想要的功能:
db.collection.aggregate([
    { "$project": { 
        "x": 1,
        "y": { 
            "$cond": [
                { "$ifNull": [ "$y.0", null] },
                "$y",
                { "$map": {
                    "input": ["A"],
                    "as": "el",
                    "in": "$y"
                }}
            ]
        }
    }}
])

所以,这些首要条件通过基本测试数组元素的“第一个索引”的存在来确定该元素是否为数组。如果条件为真,则使用现有元素,即数组。

如果条件不为真,则通过$map函数和单个“虚拟”数组元素将该元素“转换”为数组。

输出结果正是您想要的:

{
    "_id" : ObjectId("557f9d9d655c7c61fdcb7909"),
    "x" : 1,
    "y" : [
            {
                    "c" : 2,
                    "i" : 3
            }
    ]
}
{
    "_id" : ObjectId("557f9d9d655c7c61fdcb790a"),
    "x" : 1,
    "y" : [
            {
                    "c" : 4,
                    "i" : 5
            },
            {
                    "c" : 6,
                    "i" : 7
            }
    ]
}

我建议您尽可能修改文档,使其在集合中实际包含一个数组元素,而不是将其纳入管道。类似于这样的内容:
db.collection.find({ "y.0": { "$exists": false } }).forEach(function(doc) {
    db.collection.update(
        { "_id": doc._id },
        { "$set": { "y": [doc.y] } }
    )
})

这个很好用,我还需要理解它,但是它很好用。非常感谢。我不能投票,但如果可以的话,我会投的。 - Raul Martinez
@RaulMartinez 您可能还没有足够的权限来“upvote”一个答案,但您可以接受一个答案。 - user3561036

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接