【问题标题】:mongodb aggregate unwind array and no arraymongodb聚合展开数组并且没有数组
【发布时间】:2015-08-31 17:39:03
【问题描述】:

无论元素是否为数组,我都在尝试使用 $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 来创建一个数组,但是如何保留未触及的数组元素而只保留$push 没有数组元素?

我试过了:

{$group : {"_id" : "$x", "myArray" : {$push : {$cond : {if : "$isArray", then : "$y", else : ["$y"]}}}}}

使用上面的代码,我尝试将所有元素置于同一级别,但由于["$y"] 返回的正是(["$y"]),因此没有评估,只是一个包含字符串的数组。

我不想 $unwind 一个空数组,我想将一个非数组元素转换为一个数组元素,这样我就可以 $unwind。

我们将不胜感激。

【问题讨论】:

  • 我不明白您关于将样本更改为相同内容的评论。第一个样本包含“y”的数组和非数组元素,第二个是我所定义的,所有“y”元素都是数组。关于可能的重复,我认为这不是我的情况,因为我没有空数组。我有一个非数组元素,我想转换成数组,这样我就可以 $unwind.
  • 我同意这不是一个好主意,但我没有写那个集合,现在改变它不是一个选项。

标签: mongodb aggregation-framework


【解决方案1】:

$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] } }
    )
})

【讨论】:

  • 这很好用,我还是要理解它,但它很好用。非常感谢。我不能投票,但如果可以的话,我会的。
  • @RaulMartinez 您可能还没有“投票”答案所需的特权,但您可以accept one
猜你喜欢
  • 1970-01-01
  • 2019-04-10
  • 2015-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-25
  • 2021-07-20
相关资源
最近更新 更多