获取数组中每个索引的子文档元素计数并更新子文档键 - 数组中的子文档(IN MONGODB)

Posted

技术标签:

【中文标题】获取数组中每个索引的子文档元素计数并更新子文档键 - 数组中的子文档(IN MONGODB)【英文标题】:Getting subdocument element's count per index inside an array and updating the subdocument key - subdocument in array(IN MONGODB) 【发布时间】:2014-04-01 01:35:10 【问题描述】:

如何获取数组中子文档元素的计数以及如何在 MongoDB 中更新子文档的键

例如,以下是存储在 mongodb 中的整个文档:


    "CompanyCode" : "SNBN",
    "EventCode" : "ET00008352",
    "EventName" : "Sunburn Presents Avicii India Tour",
    "TktDetail" : [ 
        
            "Type" : "Category I",
            "Qty" : 
                "10-Dec" : 
                    "value" : 58
                ,
                "11-Dec" : 
                   "value" : 83
                ,
                "12-Dec" : 
                   "value" : 100
                 
            
        , 
        
            "Type" : "Category II",
            "Qty" : 
                "10-Dec" : 
                   "value" : 4
                ,
                "11-Dec" : 
                    "value" : 7
                ,
                "12-Dec" : 
                    "value" : 8
                
            
        , 
        
            "Type" : "PRICE LEVEL 1",
            "Qty" : 
                "11-Dec" : 
                    "value" : 2
                
            
        , 
        
            "Type" : "CatIV",
            "Qty" : 
                "18-Dec" : 
                    "value" : 20
                
            
        
    ],
    "TransDate" : [ 
        "10-Dec-2013", 
        "11-Dec-2013", 
        "12-Dec-2013", 
    ],
    "VenueCode" : "SNBN",
    "VenueName" : "Sunburn",
    "_id" : ObjectId("52452db273b92012c41ad612")

这里的 TktDetail 是一个数组,里面有一个包含多个元素的 Qty 子文档,我想知道如何获取每个索引 Qty 内的元素计数?

例如,TktDetail 数组的第 0 个索引包含 1 个 Qty 子文档,该子文档的元素计数为 3,而第 3 个索引在 Qty 子文档中的元素计数为 1。

如果我想更新 subdoc 键,例如,我想将 Qty 中的日期从“10-Dec”更新为“10-Dec-2013”​​,怎么可能?

提前致谢,期待尽快回复..

【问题讨论】:

有人(还不是我)刚刚对你投了反对票,因为你没有像网站要求你做的那样格式化你的数据块。 DONT SHOUT 一切都以粗体显示。未来的注意事项。但是现在可能会得到一些帮助。 现在。您的问题是(澄清)您想要更新 Qty 下子文档中的值。对吗? 感谢 Neil 为我提供未来注意事项的建议。我不想更新 Qty 中的 value 字段,我想更新存储在数组 TktDetail 中的 Qty 中的键名,例如:如果它是“10-Dec”,那么我想将其更新为“10 -2013 年 12 月”。 我也想知道,我怎样才能得到每个索引数量内的元素数量,第 0 个索引的数量有 3 作为计数,第 3 个索引的数量有 1 作为计数,以dis方式? 【参考方案1】:

所以这里的第一件事是您实际上问了 两个 问题,即 “我如何计算 Qty 下的项目数?”“如何更改名称?”。现在虽然通常不相关,但我会将它们视为同一事物。

您需要做的是更改您的架构,在此过程中,我将允许您获取项目数,并鼓励您将这些字段名称更改为好吧。具体来说,您需要这样的架构:

"TktDetail" : [ 
    
        "Type" : "Category I",
        "Qty" : [
             "date": ISODate("2013-12-10T00:00:00.000Z") , "value" : 58  ,
             "date": ISODate("2013-12-11T00:00:00.000Z"), "value" : 83  ,
             "date": ISODate("2013-12-01T00:00:00.000Z"), "value" : 100 ,
        ]
    ,

所有血淋淋的细节都在my answer here 中,用于类似的问题。但问题基本上是,当你以你拥有的方式使用 子文档 时,你正在破坏你对它进行任何有意义的查询操作的机会,因为你必须 指定到达那里的完整路径。

answer 有更多细节,但情况是你真的想要一个数组。权衡一下,更新有点困难,特别是考虑到您有 嵌套数组,但它更容易添加并且更容易查询。

此外,相关的,将您的日期更改为日期和不是字符串。字符串对于 MongoDB 内部的比较不好。将它们设置为适当的 BSON 日期(注意我将它们剪辑到一天的开始),您可以比较、查询范围并做有用的事情。您的应用程序代码会很高兴,因为驱动程序将返回一个真实日期对象,而不是您必须“双向”操作的东西。

所以一旦您已经阅读、理解并实施了这一点,然后开始计数:

db.collection.aggregate([

    // Unwind the TktDetail array to de-normalize
    "$unwind": "$TktDetail",

    // Also Unwind the Qty array
    "$unwind": "$Qty" ,

    // Get some group information and count the entries
    "$group":  
        "_id": 
            "_id": "$_id,
            "EventCode": "$EventCode",
            "Type": "$TktDetail.Type"
        ,
        "Qty": "$sum": 1 
    ,

    // Project nicely
    "$project":  
        "_id": 0,
        "EventCode": "$_id.EventCode",
        "Type: "$_id.Type",
        "Qty": 1,
    ,

    // Let's even sort it 
    "$sort":  "EventCode": 1, "Qty" -1 

])

这样我们就可以通过Type 获得Qty 中每个EventCode 中的项目的count 个,Qty 从高到低排序。

如果不加载和遍历代码中的每个文档,在您当前的架构上不可能

原来如此。现在,如果您想 忽略 并只是更改 sub-document 键名,那么您需要删除键和基础文档并替换为新的键名,使用更新:

db.collection.update(
     EventCode: "ET00008352",
     $unset: "TktDetail.0.Qty.10-Dec": "" 
)

db.collection.update(
     EventCode: "ET00008352",
     $set: "TktDetail.0.Qty.10-Dec-2013":  value: 58  
)

您需要为您拥有的每个项目执行此操作。

因此,您要么进行架构转换,要么进行 大量 工作以更改密钥。对我自己来说,我会正确地做,并且只做一次,这样我以后就不会遇到下一个问题了。

【讨论】:

我非常感谢您的回答,但是您要求我更改集合架构的第一个解决方案,在将来使用 $(Positional operator) 更新时会产生问题,因为它不是支持超过 1 级,数量将在 2 级,这就是我将其“数量”视为子文档而不是嵌套数组的原因。 Second 是一个已知的解决方案,我不能使用它,因为我想在不知道键名的情况下遍历 Qty 并更新它。 @SurajMishra 我很清楚位置更新的问题,因此我说这可能有些困难但并非不可能。如果有的话,应该在这个结构中被视为子文档的唯一项目是TktDetail部分,这使得其他一些操作更加困难,但删除了位置更新问题。这是最少的路径问题,因此是最好的地方。即使您知道您必须使用 $set 和 $unset 做什么,也没有没有其他方法。如果您需要更好地解释更改后的结构,我可以这样做。

以上是关于获取数组中每个索引的子文档元素计数并更新子文档键 - 数组中的子文档(IN MONGODB)的主要内容,如果未能解决你的问题,请参考以下文章

如何使用php更新mongodb中具有键和值的子文档

如何使用php更新mongodb中具有键和值的子文档

如何填充作为另一个文档的数组元素的子文档的字段?

子文档键上的 MongoDB 索引

子文档键上的 MongoDB 索引

仅返回嵌套数组中匹配的子文档元素