mongodb中的多重限制条件
我有一个集合,其中一个字段是“类型”。 我希望得到每种类型的一些值,具体取决于所有类型相同的条件。 就像我想要类型A的2个文档,类型B的2个文档。 如何在单个查询中执行此操作? 我正在使用Ruby Active Record。
一般来说,你所描述的是围绕MongoDB社区的一个相对常见的问题,我们可以将其描述为“前n
结果问题”。 这是给定一些可能以某种方式排序的输入,如何在不依赖于数据中的任意索引值的情况下获得前n
结果。
MongoDB有第$first
运算符,它可用于聚合框架 ,它处理问题的“前1”部分,因为这实际上是在分组边界上找到的“第一”项,例如“类型”。 但是,获得超过“一个”的结果当然会涉及更多。 关于修改其他运算符以处理n
结果或“限制”或“切片”,有一些JIRA问题。 特别是SERVER-6074 。 但问题可以通过几种方式解决。
用于MongoDB存储的rails Active Record模式的流行实现是Mongoid和Mongo Mapper ,它们都允许通过.collection
访问器访问“本机”mongodb集合函数。 这是您基本上需要能够使用本机方法,例如.aggregate() ,它支持比一般Active Record聚合更多的function。
这是一个使用mongoid的聚合方法,但是一旦您有权访问本机集合对象,通用代码就不会改变:
require "mongoid" require "pp"; Mongoid.configure.connect_to("test"); class Item include Mongoid::Document store_in collection: "item" field :type, type: String field :pos, type: String end Item.collection.drop Item.collection.insert( :type => "A", :pos => "First" ) Item.collection.insert( :type => "A", :pos => "Second" ) Item.collection.insert( :type => "A", :pos => "Third" ) Item.collection.insert( :type => "A", :pos => "Forth" ) Item.collection.insert( :type => "B", :pos => "First" ) Item.collection.insert( :type => "B", :pos => "Second" ) Item.collection.insert( :type => "B", :pos => "Third" ) Item.collection.insert( :type => "B", :pos => "Forth" ) res = Item.collection.aggregate([ { "$group" => { "_id" => "$type", "docs" => { "$push" => { "pos" => "$pos", "type" => "$type" } }, "one" => { "$first" => { "pos" => "$pos", "type" => "$type" } } }}, { "$unwind" => "$docs" }, { "$project" => { "docs" => { "pos" => "$docs.pos", "type" => "$docs.type", "seen" => { "$eq" => [ "$one", "$docs" ] }, }, "one" => 1 }}, { "$match" => { "docs.seen" => false }}, { "$group" => { "_id" => "$_id", "one" => { "$first" => "$one" }, "two" => { "$first" => { "pos" => "$docs.pos", "type" => "$docs.type" } }, "splitter" => { "$first" => { "$literal" => ["one","two"] } } }}, { "$unwind" => "$splitter" }, { "$project" => { "_id" => 0, "type" => { "$cond" => [ { "$eq" => [ "$splitter", "one" ] }, "$one.type", "$two.type" ] }, "pos" => { "$cond" => [ { "$eq" => [ "$splitter", "one" ] }, "$one.pos", "$two.pos" ] } }} ]) pp res
文档中的命名实际上并未被代码使用,而“First”,“Second”等所示数据中的标题实际上只是为了说明您确实从列表中获取了“前2”文档。结果。
因此,这里的方法主要是创建一个由您的密钥“分组”的文档的“堆栈”,例如“类型”。 这里的第一件事是使用$first
运算符从该堆栈中获取“第一个”文档。
后续步骤匹配堆栈中的“see”元素并过滤它们,然后使用$first
运算符再次从堆栈中取出“下一个”文档。 最后的步骤实际上是将文档返回到输入中找到的原始表单,这通常是从这样的查询中得到的结果。
所以结果当然只是每种类型的前2个文档:
{ "type"=>"A", "pos"=>"First" } { "type"=>"A", "pos"=>"Second" } { "type"=>"B", "pos"=>"First" } { "type"=>"B", "pos"=>"Second" }
在最近的答案中,有更长时间的讨论和版本以及其他解决方案:
Mongodb聚合$ group,限制数组的长度
基本上相同的事情,尽管标题和案件的目的是匹配多达10个顶级条目或更高。 那里还有一些管道生成代码用于处理更大的匹配以及根据您的数据可以考虑的一些替代方法。
您将无法仅使用类型列和必须是一个查询的约束直接执行此操作。 然而,(一如既往)有一种方法可以实现这一目标。
要查找不同类型的文档,您需要具有某种类型的附加值,平均根据您希望数据的方式分发类型。
db.users.insert({type: 'A', index: 1}) db.users.insert({type: 'B', index: 2}) db.users.insert({type: 'A', index: 3}) db.users.insert({type: 'B', index: 4}) db.users.insert({type: 'A', index: 5}) db.users.insert({type: 'B', index: 6})
然后,当使用db.users.find(index: {$gt: 2, $lt: 7})
查询项目时,您将拥有正确的项目分布。
虽然我不确定这是你在寻找什么
- Ruby on Rails迁移,将表更改为MyISAM
- 使用PostgreSQL使用ActiveRecord准备和执行语句
- 使用单表inheritance更改Rails中的ActiveRecord类的类型
- 将Postgres查询转换为Rails ActiveRecord?
- 多个数据库连接:在错误的数据库中查找schema_migrations
- 如何在n条件下在ActiveRecord中进行条件validation?
- 使用一个查询在Rails中同时使用ActiveRecord更新多个记录?
- 使用rails迁移创建缺少的自动增量属性
- Rails 3 Active Record关系顺序:使用hash而不是string