我很确定我做错了什么。请考虑以下代码:
criteria1 = Model.where(...)
criteria2 = Model.where(...)
results = (criteria1.to_a + criteria2.to_a)[offset..(offset + count_per_page - 1)]
此代码连接两个不同标准的结果,并使用给定的偏移量(分页)获得一定数量的结果。
此代码中的问题是隐含的。 to_a
方法调用实际上将条件的所有结果作为数组加载到内存中。
现在考虑一个非常庞大的集合...... to_a
调用会大大减慢所有事情。
我希望做的是这样的事情:
criteria1 = Model.where(...)
criteria2 = Model.where(...)
# A criteria, which returns results of the first criteria concatenated with results of the second criteria
criteria = criteria1 + criteria2
results = criteria.offset(offset).limit(count_per_page)
重要的是第二个标准的结果在第一个标准的结果之后
。有什么线索可以用Mongoid实现吗?
谢谢!
更新
Gergo Erdosi建议使用merge
方法。我试过用它,这不是我想要的。这里的问题如下:
criteria1 = Model.where(:name => "John", :age => "23")
criteria2 = Model.where(:name => "Bob", :gender => "male")
criteria = criteria1.merge(criteria2)
p criteria.selector
# prints: { "name" => "Bob", :age => 23, :gender => "male" }
所以这里有两个问题:
merge
不会产生OR,它会覆盖第一个查询的常用键和第二个; Model.or({ :name => "John" }, { :name => "Bob" })
或Model.in(:name => ["John", "Bob"])
结果,也不会有正确的订单。我希望第一个标准的结果先行,然后第二个标准的结果之后。我可能无法理解某些事情并且Gergo的答案是正确的。你还有其他建议吗?感谢。
更新2
谢谢Gergo帮助我。让我们在Mongo shell中尝试一个简单的例子:
// Fill out test db with some simple documents.
for (var i = 0; i < 10; ++i) { db.users.insert({ name: i % 2 ? "John" : "Bob", age: Math.round(Math.random() * 100) }); }
// These queries give me the same order of documents.
db.users.find({ name: { $in: ["Bob", "John"] } });
db.users.find({ $or: [{ name: "Bob" }, { name: "John" }] });
// Like this:
{ "_id" : ObjectId("53732076b110ab9be7619a8e"), "name" : "Bob", "age" : 69 }
{ "_id" : ObjectId("53732076b110ab9be7619a8f"), "name" : "John", "age" : 63 }
{ "_id" : ObjectId("53732076b110ab9be7619a90"), "name" : "Bob", "age" : 25 }
{ "_id" : ObjectId("53732076b110ab9be7619a91"), "name" : "John", "age" : 72 }
// ...
// But I wish to get concatenated results of these queries:
db.users.find({ name: "Bob" });
db.users.find({ name: "John" });
// Like this (results of the first criteria go first):
{ "_id" : ObjectId("53732076b110ab9be7619a8e"), "name" : "Bob", "age" : 69 }
{ "_id" : ObjectId("53732076b110ab9be7619a90"), "name" : "Bob", "age" : 25 }
// ...
{ "_id" : ObjectId("53732076b110ab9be7619a8f"), "name" : "John", "age" : 63 }
{ "_id" : ObjectId("53732076b110ab9be7619a91"), "name" : "John", "age" : 72 }
// ...
注意,我不能在这里使用简单的排序,因为实际应用程序中的数据更复杂。在实际应用中,标准如下:
// query variable is a string
exact_match_results = Model.where(:name => query)
inexact_match_results = Model.where(:name => /#{query}/i)
所以我们不能在这里按字母顺序排序。
答案 0 :(得分:4)
使用merge
方法:
criteria = criteria1.merge(criteria2)
results = criteria.offset(offset).limit(count_per_page)
您可以在method description。
中查看详细信息 修改:正如所指出的,merge
不会产生OR查询。
irb(main):010:0> Model.where(name: 'John').merge(Model.where(name: 'Bob'))
=> #<Mongoid::Criteria
selector: {"name"=>"Bob"}
options: {}
class: Model
embedded: false>
在这种情况下,这不是预期的行为。原因是merge
使用行为方式Hash.merge
。来自Criteria.merge
的{{3}}代码:
selector.merge!(criteria.selector)
这可以说明为:
irb(main):011:0> {name: 'John'}.merge({name: 'Bob'})
=> {:name=>"Bob"}
因此,就如何以结果为OR查询的方式合并两个条件提出一般性建议并不容易。但随着标准的微小变化,这是可能的。例如:
criteria1 = Model.any_of(name: 'John').where(age: '23')
criteria2 = Model.any_of(name: 'Bob').where(gender: 'male')
合并的结果是OR查询,其中包含两个名称:
irb(main):014:0> criteria1.merge(criteria2)
=> #<Mongoid::Criteria
selector: {"$or"=>[{"name"=>"John"}, {"name"=>"Bob"}], "age"=>"23", "gender"=>"male"}
options: {}
class: Model
embedded: false>