Вопрос о привязке нескольких критериев any #

У меня есть требование, когда мне нужно запустить запрос 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" с использованием привязки критериев?

Ответы

Ответ 1

Вы можете сделать это, избегая any_of.

criteria = Collection.where('$or' => [{"field1" => "value1"}, {"field2" => "value2"}])
criteria = criteria.where('$or' => [{"field3" => "value3"}, {"field4" => "value4"}])

Ответ 2

вы можете написать это с помощью mongoid 2.4.0:

  Collection.all_of({"$or" => [{"field1" => "value1"}, {"field2" => "value2"}]}, {"$or" => [{"field3" => "value3"}, {"field4" => "value4"}]})

Ответ 3

Для 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, прежде чем добавлять дополнительные критерии.

Ответ 4

Мне потребовалось навсегда, чтобы все было правильно, но это то, что сработало для меня:

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/Мопед)

Ответ 5

Это все еще так. Я смог обойти это только с помощью API-интерфейса Ruby Mongo Driver.