Ответ 1
Вы можете сделать это, избегая any_of.
criteria = Collection.where('$or' => [{"field1" => "value1"}, {"field2" => "value2"}])
criteria = criteria.where('$or' => [{"field3" => "value3"}, {"field4" => "value4"}])
У меня есть требование, когда мне нужно запустить запрос MongoDB, как показано ниже:
db.collection.find({ $or : [{"field1" : "value1"}, {"field2" : "value2"}], $or : [{"field3" : "value3"}, {"field4" : "value4"}]})
то есть.
(field1 == value 1 or field2 == value2) and (field3 == value3 or field4 == value4)
Я хочу добиться этого путем привязки критериев, потому что запрос формируется динамически из разных частей кода. Но если я попытаюсь сделать что-то вроде следующего
criteria = Collection.any_of({"field1" => "value1"}, {"field2" => "value2"}) criteria = criteria.any_of({"field3" => "value3"}, {"field4" => "value4"})
Я получаю результирующий запрос, где все они объединены в один $или утверждение вроде
db.collection.find({ $or : [{"field1" : "value1"}, {"field2" : "value2"}, {"field3" : "value3"}, {"field4" : "value4"}]})
Каков способ достижения "и" двух "any_of" с использованием привязки критериев?
Вы можете сделать это, избегая any_of.
criteria = Collection.where('$or' => [{"field1" => "value1"}, {"field2" => "value2"}])
criteria = criteria.where('$or' => [{"field3" => "value3"}, {"field4" => "value4"}])
вы можете написать это с помощью mongoid 2.4.0:
Collection.all_of({"$or" => [{"field1" => "value1"}, {"field2" => "value2"}]}, {"$or" => [{"field3" => "value3"}, {"field4" => "value4"}]})
Для Mongoid 3 и 4 существует относительно хороший способ привязки или критериев без слияния.
TL; DR
MyModel.all_of(MyModel.xxx.selector, MyModel.yyy.selector)
Монгоидный сопровождающий Дурран показал вышеупомянутый трюк в этом вопросе Гитуба: https://github.com/mongoid/mongoid/issues/2170
Вы можете произвольно задавать критерии, используя ту же технику и некоторые трюки массивов, как это:
selectors = []
selectors << MyModel.search(term) if term
selectors << MyModel.some_any_of if some_condition
selectors << MyModel.some_other_any_of if some_other_condition
...
MyMode..all_of(*selectors)
Каждая строка добавит еще и условие.
Возможно, стоит отметить, что вам не нужно создавать каждый селектор из модели. Вы можете получить начальную область обратно из вашей системы разрешений или что-то вроде просто вызвать .selector, прежде чем добавлять дополнительные критерии.
Мне потребовалось навсегда, чтобы все было правильно, но это то, что сработало для меня:
scope :for_user, lambda {|user|
any_of(
{recipient_id: Moped::BSON::ObjectId.from_string(user.id)},
{sender_id: Moped::BSON::ObjectId.from_string(user.id)},
{sender_email: user.email},
{recipient_email: user.email}
)
}
Вам нужно обязательно обернуть отдельные критерии для условия $or
в {}
, чтобы он правильно вложил ИЛИ. (Использование Mongoid3/Мопед)
Это все еще так. Я смог обойти это только с помощью API-интерфейса Ruby Mongo Driver.