有条件地评估要返回的数组元素

时间:2014-02-03 11:14:31

标签: mongodb aggregation-framework

考虑到以下数据,我想在MongoDB的Array字段中返回默认文档ID的结果。让我们调用集合books。样本收集数据如下所示:

[
  {
     name: "Book1",
     refs: [{ oid: "object1" }, { oid: "object2" }, {oid: "object5", default: true }]
  },
  {
    name: "Book2",
    refs: [{ oid: "object3" }, { oid: "object5", default: true }, { oid: "object7" }]
 },
 {
    name: "Book3",
    refs: [{ oid: "object4" }, { oid: "object2" }]
 },
 {
   name: "Book4",
   refs: [{ oid: "object5" }, { oid: "object4", default: true } ]
 }
]

好。因此,为了简洁起见,很多关键值都在那里,但这并没有改变这一点。

这里所需的逻辑如下:

  1. refs阵列字段中找到并返回默认值为 true
  2. 的文档
  3. 如果数组中没有匹配的文档,则返回数组中的第一个文档
  4. 遵循这个逻辑,我真的希望看到返回的内容如下:

    [
      {
        name: "Book1"
        refs: [{oid: "object5", default: true }]
      },
      {
        name: "Book2",
        refs: [{ oid: "object5", default: true }]
      },
      {
        name: "Book3",
        refs: [{ oid: "object4" }]
      },
      {
        name: "Book4",
        refs: [{ oid: "object4" }]
      }
    ]
    

    现在我知道聚合管道中有$cond运算符,但是这个条件的一部分似乎必然会在default属性没有的投影上获得$slice存在于文档上(可能设置为true但存在应该足够)。

    此逻辑模式依赖于使用$pull删除元素匹配的预期结果:

    oid: "object5"
    

    在每个文档数组中,然后仍然能够回退到查询中数组的第一个元素

    所以我正在寻找一些强大 fu才能返回结果。

    解决方案不能在主文档中添加另一个字段,引用数组文档中默认字段的值。没有这个实际上就是重点,因此$pull操作在multi文档更新模式下有效。

    修改

    这是一个查询,我的意思是当未设置默认属性时,我想要列出数组中的第一个元素。每一次。

    字符串是样本数据,所以不要依赖词汇顺序。在现实世界中,所有object#引用都可能是真正的 $ oid

    这可能最终成为赏金。如上所述,在更新的容差范围内接受模式更改。在最坏的情况下,这些发现是JIRA问题的合理依据。

    作为参考,我基于this post的答案开始思考,这主要是为了重新思考架构以适应目标。

    好狩猎。

    P.S和Webscale,人们。集合的更新需要在没有迭代的情况下进行,因为可能存在真正的(哦网络规模!)大量数据。

2 个答案:

答案 0 :(得分:2)

以下是使用MongoDB 2.4.9中的聚合框架的示例,我认为这样可以实现您所追求的结果:

db.books.aggregate(

    // Unwind the refs array
    { $unwind: "$refs" },

    // Sort by refs.default descending so "true" values will be first, nulls last
    { $sort: {
        "refs.default" : -1
    }},

    // Group and take the first ref; should either be "default:true" or first element
    { $group: {
        _id: "$_id",
        name: { $addToSet: "$name" },
        refs: { $first: "$refs" }
    }},

    // (optional) Sort by name to match the example output
    { $sort: {
        name: 1,
    }},

    // (optional) Clean up output
    { $project: {
        _id: 0,
        name: 1,
        refs: 1
    }}
)

示例结果:

{
    "result" : [
        {
            "name" : [
                "Book1"
            ],
            "refs" : {
                "oid" : "object5",
                "default" : true
            }
        },
        {
            "name" : [
                "Book2"
            ],
            "refs" : {
                "oid" : "object5",
                "default" : true
            }
        },
        {
            "name" : [
                "Book3"
            ],
            "refs" : {
                "oid" : "object4"
            }
        },
        {
            "name" : [
                "Book4"
            ],
            "refs" : {
                "oid" : "object4",
                "default" : true
            }
        }
    ],
    "ok" : 1
}

注意:

  • 这假设了refs的排序顺序行为,其中缺少“default:true”。在简短的测试中,原始顺序似乎被保留,因此数组的“第一个”元素是预期的。

  • 由于使用了聚合运算符,输出name是单个元素数组,refs成为嵌入对象。您可以在应用程序代码中引用正确的字段,而不是在聚合框架中进一步操作。

答案 1 :(得分:1)

我认为以下聚合查询将起作用,

db.books.aggregate(
    {$unwind:'$refs'},
    {$group:{_id:{name:'$name',def:'$refs.default'},refs:{$first:'$refs'}}},
    {$sort:{'_id.def':-1}},
    {$group:{_id:'$_id.name',refs:{$first:'$refs'}}},
    {$project:{name:'$_id',refs:1,_id:0}}
)

结果:

{
    "result" : [
            {
                    "refs" : {
                            "oid" : "object4"
                    },
                    "name" : "Book3"
            },
            {
                    "refs" : {
                            "oid" : "object5",
                            "default" : true
                    },
                    "name" : "Book1"
            },
            {
                    "refs" : {
                            "oid" : "object5",
                            "default" : true
                    },
                    "name" : "Book2"
            },
            {
                    "refs" : {
                            "oid" : "object4",
                            "default" : true
                    },
                    "name" : "Book4"
            }
    ],
    "ok" : 1

}