MongoDB中多限制条件 [英] Multiple limit condition in mongodb

查看:152
本文介绍了MongoDB中多限制条件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个集合,其中所述字段中的一个是类型。我想每种类型取决于条件是相同的所有类型的某些值。就像我想要2个文件为A型,2为这样的B型。 如何做到这一点在一个单一的查询?我使用Ruby的活动记录。

I have a collection in which one of the field is "type". I want to get some values of each type depending upon condition which is same for all the types. Like I want 2 documents for type A, 2 for type B like that. How to do this in a single query? I am using Ruby Active Record.

推荐答案

通常你所描述的是围绕MongoDB的社区里面,我们可以称之为顶级 N 导致的问题。这是当给予一定的投入是在某些方面可能会进行排序,如何让高层 N 的结果,而不在数据依靠任意索引值。

Generally what you are describing is a relatively common question around the MongoDB community which we could describe as the "top n results problem". This is when given some input that is likely sorted in some way, how to get the top n results without relying on arbitrary index values in the data.

MongoDB中有 第$ 运营商是提供给聚合框架其中涉及的问题顶部1的一部分,因为这实际上是发生在一个分组的边界,找到了第一的项目,如你的类型。但是,越来越多一,当然结果变得有点棘手。还有一些JIRA问题在这个有关修改其他经营者应对 N 结果或限制或切片。值得注意的是 SERVER-6074 。但这个问题可以通过几种方式来处理。

MongoDB has the $first operator which is available to the aggregation framework which deals with the "top 1" part of the problem, as this actually takes the "first" item found on a grouping boundary, such as your "type". But getting more than "one" result of course gets a little more involved. There are some JIRA issues on this about modifying other operators to deal with n results or "restrict" or "slice". Notably SERVER-6074. But the problem can be handled in a few ways.

在轨活动记录模式的MongoDB的存储受欢迎的实现是 Mongoid 和<一HREF =htt​​p://mongomapper.com/相对=nofollow>蒙戈映射,都允许通过 .collection 访问。这就是你基本上需要能够使用本地方法,如。骨料()支持比一般的活动记录聚集更多的功能。

Popular implementations of the rails Active Record pattern for MongoDB storage are Mongoid and Mongo Mapper, both allow access to the "native" mongodb collection functions via a .collection accessor. This is what you basically need to be able to use native methods such as .aggregate() which supports more functionality than general Active Record aggregation.

下面是mongoid聚合方法,虽然一般的code不会改变,一旦你有访问本地集合对象:

Here is an aggregation approach with mongoid, though the general code does not alter once you have access to the native collection object:

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

在文件的命名实际上是不使用code,和标题所示的第一的数据,第二等等,真的只是为了表明你确实得到顶2 从上市作为一个结果文件。

The naming in the documents is actually not used by the code, and titles in the data shown for "First", "Second" etc, are really just there to illustrate that you are indeed getting the "top 2" documents from the listing as a result.

因此​​,这里的做法实质上是打造分组,由你的关键的文件,如类型的堆栈。这里的第一件事情是使用采取从堆栈中的第一的文件 $首先 运营商。

So the approach here is essentially to create a "stack" of the documents "grouped" by your key, such as "type". The very first thing here is to take the "first" document from that stack using the $first operator.

后续的步骤与从堆栈中看到的元素和筛选它们,然后你走下一个文件从堆栈中使用的 $首先 运营商。在那里的最后步骤是真的justx在如输入,这是通常什么是从这样一个查询预期找到的文件返回到原来的形式。

The subsequent steps match the "seen" elements from the stack and filter them, then you take the "next" document off of the stack again using the $first operator. The final steps in there are really justx to return the documents to the original form as found in the input, which is generally what is expected from such a query.

所以结果当然是,就在上面2个文件为每种类型的:

So the result is of course, just the top 2 documents for each type:

{ "type"=>"A", "pos"=>"First" }
{ "type"=>"A", "pos"=>"Second" }
{ "type"=>"B", "pos"=>"First" }
{ "type"=>"B", "pos"=>"Second" }

有一个较长的讨论的这个和版本以及其他的解决方案中该最近的答案:

There was a longer discussion and version of this as well as other solutions in this recent answer:

MongoDB的汇聚$组,限制数组的长度

本质上是一回事,尽管标题和这种情况下,一直在寻找匹配到10上方的条目或更大。有一些管道代code有作为处理大的匹配,以及可以根据您的数据被视为一些其他方法。

Essentially the same thing despite the title and that case was looking to match up to 10 top entries or greater. There is some pipeline generation code there as well for dealing with larger matches as well as some alternate approaches that may be considered depending on your data.

这篇关于MongoDB中多限制条件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆