在 MongoDb 中使用 addToSet 时保持原始文档的顺序

Posted

技术标签:

【中文标题】在 MongoDb 中使用 addToSet 时保持原始文档的顺序【英文标题】:Maintain order as original document while using addToSet in MongoDb 【发布时间】:2021-07-09 04:33:16 【问题描述】:

我阅读了文档,发现 addToSet 不保证顺序。 但是有什么办法可以将订单保留为原始文档。 我的查询是:-

    aggregate([$match: 
      $or:["Name.No":"119","Name.No":"120"]
    , $project: 
      x:$objectToArray:"$Results"
    ,$unwind: "$x",$group: _id: "$x.k", distinctVals: $addToSet: "$x.v.TCR"])

样本数据:

"Name" : "No." : "119","Time" : "t",
"Results":"K1" : "Counters" : x, "TCR" : ["Name" : "K11", "Result" : "PASSED", 
                                             "Name" : "K12","Result" : "FAILED",
                                             "Name" : "K13","Result" : "PASSED"]
                    ,
            "K2" : "Counters": y, "TCR" : ["Name" : "K21","Result" : "PASSED",              
                                            "Name" : "K22","Result" : "PASSED"]
                      
                    
            
           

工作2;

 "Name" : "No." : "120","Time" : "t1",
"Results":"K1" : "Counters" : x, "TCR" : ["Name" : "K11", "Result" : "PASSED", 
                                             "Name" : "K12","Result" : "PASSED",
                                             "Name" : "K13","Result" : "FAILED"]
                    ,
            "K3" : "Counters": y, "TCR" : ["Name" : "K31","Result" : "PASSED",              
                                            "Name" : "K32","Result" : "PASSED"]
                      
                    
            
           

预期;

 "Name" : "No." : "119-120","Time" : "lowest(t,t1)",
"Results":"K1" : "Counters" : x, "TCR" : ["Name" : "K11", "Result" : "PASSED", 
                                             "Name" : "K12","Result" : "PASSED",
                                             "Name" : "K13","Result" : "PASSED"]
                    ,
            "K2" : "Counters": y, "TCR" : ["Name" : "K21","Result" : "PASSED",              
                                            "Name" : "K22","Result" : "PASSED"]
                      
                    ,
             "K3" : "Counters": y, "TCR" : ["Name" : "K31","Result" : "PASSED",              
                                            "Name" : "K32","Result" : "PASSED"]
                      
                    
            
           

我想保持与原始文档相同的顺序,而且每次文档都会更改,所以我无法根据任何参数进行排序。

【问题讨论】:

您能否在查询中添加示例数据mongoplayground.net 如何定义顺序?假设您输入的是[20, 10, 20]。你想得到什么输出? [10, 20] 还是 [20,10]?来自@turivishal 的解决方案给出了[20,10] 添加了现在有问题的示例数据。 【参考方案1】: 使用$objectToArray将结果对象转换为数组格式 $unwind解构Results数组 $unwind解构Results.v.TCR数组 $match 过滤PASSED 结果 $group by Results.k 并获得第一个Name,获得第一个Counters,构造Results.v.TCR 的数组 $group by null 得到最小值Time,构造No的唯一数组,在键值对中构造Results数组,$reduce迭代TCR的循环并删除重复文档 $project 显示必填字段,使用 $arrayToObjectResults 数组转换为对象,将 No 数组转换为字符串并使用“-”连接
db.collection.aggregate([
   $addFields:  Results:  $objectToArray: "$Results"   ,
   $unwind: "$Results" ,
   $unwind: "$Results.v.TCR" ,
   $match:  "Results.v.TCR.Result": "PASSED"  ,
  
    $group: 
      _id: "$Results.k",
      Name:  $first: "$Name" ,
      Counters:  $first: "$Results.v.Counters" ,
      TCR:  $push: "$Results.v.TCR" 
    
  ,
  
    $group: 
      _id: null,
      Time:  $min: "$Name.Time" ,
      No:  $addToSet: "$Name.No" ,
      Results: 
        $push: 
          k: "$_id",
          v: 
            Counters: "$Counters",
            TCR: 
              $reduce: 
                input: "$TCR",
                initialValue: [],
                in: 
                  $cond: [
                    
                      $in: [
                        
                          Name: "$$this.Name",
                          Result: "$$this.Result"
                        ,
                        "$$value"
                      ]
                    ,
                    "$$value",
                    
                      $concatArrays: [
                        "$$value",
                        [
                          
                            Name: "$$this.Name",
                            Result: "$$this.Result"
                          
                        ]
                      ]
                    
                  ]
                
              
            
          
        
      
    
  ,
  
    $project: 
      _id: 0,
      Results:  $arrayToObject: "$Results" ,
      Name: 
        Time: "$Time",
        No: 
          $reduce: 
            input: "$No",
            initialValue: "",
            in: 
              $concat: [
                "$$value",
                 $cond: [ $eq: ["$$value", ""], "", "-"] ,
                "$$this"
              ]
            
          
        
      
    
  
])

Playground

“。” (点)在“不”。字段无效,可能会导致 mongodb 查询操作出现问题,我建议不要使用“。” (点)作为字段名。

【讨论】:

no..还是不行,push也没有保留订单。 您能否在您的问题中发布示例文档和预期结果。 使用示例数据更新了问题 根据您的查询,您的文档无效,您确定 Results 已经是数组吗?因为您已使用 x:$objectToArray:"$Results" 将其从对象转换为数组,因此不需要 $project 阶段。 您现在可以检查一下吗

以上是关于在 MongoDb 中使用 addToSet 时保持原始文档的顺序的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB聚合,如何在组管道中addToSet数组的每个元素

带有一些逻辑的 MongoDB $addToSet

带有一些逻辑的 MongoDB $addToSet

如何在 Mongoose 中使用 $addToSet 和 ObjectId 数组?

mongodb 修改操作

使用aggregate在MongoDB中查找重复的数据记录