草庐IT

mongodb - 计算有多少文档包含一个字段

coder 2023-05-05 原文

我有这三个 MongoDB 文档:

{ 
    "_id" : ObjectId("571094afc2bcfe430ddd0815"), 
    "name" : "Barry", 
    "surname" : "Allen", 
    "address" : [
        {
            "street" : "Red", 
            "number" : NumberInt(66), 
            "city" : "Central City"
        }, 
        {
            "street" : "Yellow", 
            "number" : NumberInt(7), 
            "city" : "Gotham City"
        }
    ]
}

{ 
    "_id" : ObjectId("57109504c2bcfe430ddd0816"), 
    "name" : "Oliver", 
    "surname" : "Queen", 
    "address" : {
        "street" : "Green", 
        "number" : NumberInt(66), 
        "city" : "Star City"
    }
}
{ 
    "_id" : ObjectId("5710953ac2bcfe430ddd0817"), 
    "name" : "Tudof", 
    "surname" : "Unknown", 
    "address" : "homeless"
}

address 字段是第一个文档中的对象的 Array、第二个文档中的 ObjectString在第三。 我的目标是找出我的集合中有多少文档包含字段 address.street。在这种情况下,正确的计数是 1,但通过我的查询,我得到了两个:

db.coll.find({"address.street":{"$exists":1}}).count()

我也尝试过 map/reduce。它有效,但速度较慢;所以如果可能的话,我会避免它。

最佳答案

这里的区别在于 .count() 操作在返回字段存在的“文档”计数时实际上是“正确的”。因此,一般考虑可分解为:

如果你只想排除带有数组字段的文档

那么最有效的方法是排除那些“街道”是“地址”属性的文档作为“数组”,然后只需使用查找 0 的点符号属性> 排除项中不存在的索引:

db.coll.find({
  "address.street": { "$exists": true },
  "address.0": { "$exists": false }
}).count()

在这两种情况下,$exists 都作为 native 编码的运算符测试执行正确且高效的工作。

如果您打算计算字段出现次数

如果您实际询问的是“字段计数”,其中一些“文档”包含数组条目,其中该“字段”可能出现多次。

为此,您需要您提到的聚合框架或 mapReduce。 MapReduce 使用基于 JavaScript 的处理,因此比 .count() 操作要慢得多。聚合框架还需要计算并且“将”比 .count() 慢,但不会像 mapReduce 那么多。

在 MongoDB 3.2 中,您可以通过 $sum 的扩展功能获得一些帮助处理一组值以及作为分组累加器。这里的另一个助手是 $isArray允许通过 $map 使用不同的处理方法当数据实际上是“一个数组”时:

db.coll.aggregate([
  { "$group": {
    "_id": null,
    "count": {
      "$sum": {
        "$sum": {
          "$cond": {
            "if": { "$isArray": "$address" },
            "then": {
              "$map": {
                "input": "$address",
                "as": "el",
                "in": {
                  "$cond": {
                    "if": { "$ifNull": [ "$$el.street", false ] },
                    "then": 1,
                    "else": 0
                  }
                }
              }
            },
            "else": {
              "$cond": {
                "if": { "$ifNull": [ "$address.street", false ] },
                "then": 1,
                "else": 0
              }
            }
          }
        }
      }
    }
  }}
])

早期版本依赖于更多的条件处理,以便以不同方式处理数组和非数组数据,通常需要 $unwind处理数组条目。

通过 $map 转置数组使用 MongoDB 2.6:

db.coll.aggregate([
  { "$project": {
    "address": {
      "$cond": {
        "if": { "$ifNull": [ "$address.0", false ] },
        "then": "$address",
        "else": {
          "$map": {
            "input": ["A"],
            "as": "el",
            "in": "$address"
          }
        }
      }
    }
  }},
  { "$unwind": "$address" },
  { "$group": {
    "_id": null,
    "count": {
      "$sum": {
        "$cond": {
          "if": { "$ifNull": [ "$address.street", false ] },
          "then": 1,
          "else": 0
        }
      }
    }
  }}
])

或者使用 MongoDB 2.2 或 2.4 提供条件选择:

db.coll.aggregate([
  { "$group": {
    "_id": "$_id",
    "address": { 
      "$first": {
        "$cond": [
          { "$ifNull": [ "$address.0", false ] },
          "$address",
          { "$const": [null] }
        ]
      }
    },
    "other": {
      "$push": {
        "$cond": [
          { "$ifNull": [ "$address.0", false ] },
          null,
          "$address"
        ]
      }
    },
    "has": { 
      "$first": {
        "$cond": [
          { "$ifNull": [ "$address.0", false ] },
          1,
          0
        ]
      }
    }
  }},
  { "$unwind": "$address" },
  { "$unwind": "$other" },
  { "$group": {
    "_id": null,
    "count": {
      "$sum": {
        "$cond": [
          { "$eq": [ "$has", 1 ] },
          { "$cond": [
            { "$ifNull": [ "$address.street", false ] },
            1,
            0
          ]},
          { "$cond": [
            { "$ifNull": [ "$other.street", false ] },
            1,
            0
          ]}
        ]
      }
    }
  }}
])

所以后一种形式“应该”比 mapReduce 表现好一点,但可能不会好很多。

在所有情况下,逻辑都归结为使用 $ifNull作为聚合框架的 $exists 的“逻辑”形式。与 $cond 配对,当属性实际存在时得到一个“truthfull”结果,不存在时返回一个false值。这决定了是1还是0分别通过$sum返回到整体累加中。 .

理想情况下,您拥有可以在单个 $group 中执行此操作的现代版本管道阶段,否则您需要更长的路径。

关于mongodb - 计算有多少文档包含一个字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36645838/

有关mongodb - 计算有多少文档包含一个字段的更多相关文章

  1. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  2. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  3. ruby-on-rails - 渲染另一个 Controller 的 View - 2

    我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>

  4. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  5. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  6. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  7. ruby-on-rails - 使用一系列等级计算字母等级 - 2

    这里是Ruby新手。完成一些练习后碰壁了。练习:计算一系列成绩的字母等级创建一个方法get_grade来接受测试分数数组。数组中的每个分数应介于0和100之间,其中100是最大分数。计算平均分并将字母等级作为字符串返回,即“A”、“B”、“C”、“D”、“E”或“F”。我一直返回错误:avg.rb:1:syntaxerror,unexpectedtLBRACK,expecting')'defget_grade([100,90,80])^avg.rb:1:syntaxerror,unexpected')',expecting$end这是我目前所拥有的。我想坚持使用下面的方法或.join,

  8. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  9. ruby - 为什么 SecureRandom.uuid 创建一个唯一的字符串? - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?

  10. ruby-on-rails - 在 Rails 和 ActiveRecord 中查询时忽略某些字段 - 2

    我知道我可以指定某些字段来使用pluck查询数据库。ids=Item.where('due_at但是我想知道,是否有一种方法可以指定我想避免从数据库查询的某些字段。某种反拔?posts=Post.where(published:true).do_not_lookup(:enormous_field) 最佳答案 Model#attribute_names应该返回列/属性数组。您可以排除其中一些并传递给pluck或select方法。像这样:posts=Post.where(published:true).select(Post.attr

随机推荐