使用 $unwind、$lookup 和 $group 的复杂聚合中的 mongodb 正确列表顺序

Posted

技术标签:

【中文标题】使用 $unwind、$lookup 和 $group 的复杂聚合中的 mongodb 正确列表顺序【英文标题】:mongodb correct list order in complex aggregation with $unwind, $lookup and $group 【发布时间】:2018-06-28 21:12:59 【问题描述】:

我有一个问题,使用聚合自动取消引用子对象并保持列表顺序这样做。首先:我的数据模型。让我们将其分解为两个集合(我使用简化的 id 以便于理解):

会议:


    'id': '1',
    'some': 'abc',
    'data': 'def',
    'agendaItem': [
        ObjectId('2'),
        ObjectId('3')
    ]

议程项目:


    'id': ObjectId('2'),
    'some': 'ghi',
    'data': 'jkl'
,

    'id': ObjectId('3'),
    'some': 'mno',
    'data': 'pqr'

我的单(!)查询的结果应该是这样的:


    'id': ObjectId('1'),
    'some': 'abc',
    'data': 'def',
    'agenda_items': [
        
            'id': ObjectId('2'),
            'some': 'ghi',
            'data': 'jkl'
        ,
        
            'id': ObjectId('3'),
            'some': 'mno',
            'data': 'pqr'
        
    ]

重要的部分是议程项目列表应该保持相同的顺序,id 2 必须在顶部。

目前,我使用带有展开、查找和分组的聚合来执行这样的查询:

[
    
        '$unwind': 
            'preserveNullAndEmptyArrays': True,
            'path': '$agendaItem'
        
    ,
    
        '$lookup': 
            'from': 'agenda_item',
            'as': 'agendaItem',
            'foreignField': '_id',
            'localField': 'agendaItem'
        
    ,
    
        '$unwind': 
            'preserveNullAndEmptyArrays': True,
            'path': '$agendaItem'
        
    ,
    
        '$group': 
            'agendaItem': 
            '$addToSet': '$agendaItem'
            
        
    
]

这给了我想要的结果 - 除了一个例外:列表完全混淆了,这意味着在此示例中 ObjectId('3') 在 ObjectId('2') 之前。

在 MongoDb 的这篇博文中使用 addFields:http://www.kamsky.org/stupid-tricks-with-mongodb/using-34-aggregation-to-return-documents-in-same-order-as-in-expression 是一种解决方案,但我不知道如何将它放入 $unwind + $lookup 链中。你能帮助我吗?还是我的策略完全错误?

德语背景顺便说一句:https://oparl.org/spezifikation/online-ansicht/ 和 https://mirror.oparl.org/body/5a3d010888dbe04745b24e0a/meeting

【问题讨论】:

你为什么使用 addToSet ? $addToSet 不保证维持秩序。使用$push 并在$group 阶段之前添加$sort 阶段以实现稳定排序。所以最后两个阶段应该是$sort:"agendaItem.id":1, '$group': '_id':'$id', 'agendaItem': '$push': '$agendaItem' 我想是因为我仍然有理解聚合框架的问题,所以我忽略了addToSet 的问题。但这对现有值很有用。所以后续问题:我不想让它按 id 排序,而是按照它在 MongoDB 列表中的保存方式。我想解决方案是$addField,但我不知道在哪里添加它。你能给我一个提示吗? 我猜你是在 3.4 上,因为你提到了 $addFields。只是不要 $unwind$group (它在 3.4 中不需要)。试试这个,不要尝试其他阶段db.col.aggregate([ '$lookup': 'from': 'agenda_item', 'as': 'agendaItem', 'foreignField': '_id', 'localField': 'agendaItem' ]) $addField 是我在谷歌上搜索的解决方案。这是一个新项目,所以我可以选择任何我想要的 MongoDB 版本。但是当 MongoDB 3.2 是另一个项目的当前版本时,我创建了代码 sn-p。并且:您的提示效果很好。所以这在最后一个版本中变得“更”容易了,我只是没有检查简化现在是否可以完成这项工作。非常感谢! 很遗憾,@user2683814 建议的解决方案不起作用。如果localField 是一个数组,$lookup 阶段会查找数组的所有项并输出一个数组。但是,不能保证结果字段将按照与输入数组相同的顺序输出。 【参考方案1】:

我有完全相同的问题要解决。

可以在这里找到解决方案: Aggregate $lookup does not return elements original array order

【讨论】:

以上是关于使用 $unwind、$lookup 和 $group 的复杂聚合中的 mongodb 正确列表顺序的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB $lookup 在 2 级嵌套文档上不使用 $unwind

MongoDB $lookup 在 2 级嵌套文档上不使用 $unwind

$lookup 没有 $unwind 的多个级别?

$lookup 没有 $unwind 的多个级别?

MongoDB $lookup 和 $group 返回空数组

$lookup 聚合中的 $project [重复]