我有一个以上的对象。我需要更新嵌入对象中的字段。在这里我的对象。
{
"_id" : ObjectId("50dc134bb4a6de8e6b000001"),
"emails" : [
{
"_id" : ObjectId("50dc134bb4a6de8e6b000004"),
"_type" : "Email",
"name" : "personal",
"email" : "",
"current" : false
},
{
"_id" : ObjectId("51a855763183a6301e009461"),
"_type" : "Email",
"name" : "work",
"email" : "xxx@gmail.com",
"current" : true
},
],
}
{
"_id" : ObjectId("50dc134bb4a6de8e6b000002"),
"emails" : [
{
"_id" : ObjectId("50dc134bb4a6de8e6b000067"),
"_type" : "Email",
"name" : "personal",
"email" : "",
"current" : false
},
{
"_id" : ObjectId("51a855763183a6301e004795"),
"_type" : "Email",
"name" : "work",
"email" : "xxx@gmail.com",
"current" : true
},
],
}
这是一个Contact
集合。在这里,我需要设置current : true
,其中name
是personal
。我尝试了循环功能。它工作正常。
contacts = Contact.where(:emails.elem_match => {"name" => "personal"})
contacts.each do |contact|
contact.email.where("name" => "personal").update_all(:current => true)
end
在mongodb中,我们可以编写单行查询来更新多个对象,如
db.contacts.update({"emails": {$elemMatch : {"name" : "personal"}},{ $set: {"emails.$.current":true}})
所以我想知道,是否有可能编写一行mongoid查询来更新mongoid上的多个对象。
答案 0 :(得分:1)
使用Mongoid的等效单行Ruby语句是:
Contact.where(:emails.elem_match => {"name" => "personal"}).update_all("$set" => {"emails.$.current" => true})
以下是它有效的证明。
应用程序/模型/ contact.rb
class Contact
include Mongoid::Document
embeds_many :emails
end
应用程序/模型/ email.rb
class Email
include Mongoid::Document
field :name, type: String
field :email, type: String
field :current, type: Boolean
embedded_in :contact
end
测试/单元/ contact_test.rb
require 'test_helper'
require 'pp'
class ContactTest < ActiveSupport::TestCase
def setup
Contact.delete_all
end
test '0. mongoid version' do
puts "\nMongoid::VERSION:#{Mongoid::VERSION}\nMoped::VERSION:#{Moped::VERSION}\nRails.version:#{Rails.version}"
end
test 'update all embedded objects' do
docs = [
{
"_id" => Moped::BSON::ObjectId("50dc134bb4a6de8e6b000001"),
"emails" => [
{
"_id" => Moped::BSON::ObjectId("50dc134bb4a6de8e6b000004"),
"_type" => "Email",
"name" => "personal",
"email" => "",
"current" => false
},
{
"_id" => Moped::BSON::ObjectId("51a855763183a6301e009461"),
"_type" => "Email",
"name" => "work",
"email" => "xxx@gmail.com",
"current" => true
},
],
},
{
"_id" => Moped::BSON::ObjectId("50dc134bb4a6de8e6b000002"),
"emails" => [
{
"_id" => Moped::BSON::ObjectId("50dc134bb4a6de8e6b000067"),
"_type" => "Email",
"name" => "personal",
"email" => "",
"current" => false
},
{
"_id" => Moped::BSON::ObjectId("51a855763183a6301e004795"),
"_type" => "Email",
"name" => "work",
"email" => "xxx@gmail.com",
"current" => true
},
],
}
]
Contact.collection.insert(docs)
# contacts = Contact.where(:emails.elem_match => {"name" => "personal"})
# contacts.each do |contact|
# contact.emails.where("name" => "personal").update_all(:current => true)
# end
#db.contacts.update({"emails": {$elemMatch : {"name" : "personal"}},{ $set: {"emails.$.current":true}})
Contact.where(:emails.elem_match => {"name" => "personal"}).update_all("$set" => {"emails.$.current" => true})
puts
contacts = Contact.all.to_a
contacts.each do |contact|
emails = contact["emails"].select{|email| email["name"] == "personal"}
assert_equal(true, emails.first["current"])
end
pp contacts.collect{|contact| contact.serializable_hash}
end
end
rake test
Run options:
# Running tests:
[1/2] ContactTest#test_0._mongoid_version
Mongoid::VERSION:3.1.6
Moped::VERSION:1.5.2
Rails.version:3.2.17
[2/2] ContactTest#test_update_all_embedded_objects
[{"_id"=>"50dc134bb4a6de8e6b000001",
"emails"=>
[{"_id"=>"50dc134bb4a6de8e6b000004",
"current"=>true,
"email"=>"",
"name"=>"personal"},
{"_id"=>"51a855763183a6301e009461",
"current"=>true,
"email"=>"xxx@gmail.com",
"name"=>"work"}]},
{"_id"=>"50dc134bb4a6de8e6b000002",
"emails"=>
[{"_id"=>"50dc134bb4a6de8e6b000067",
"current"=>true,
"email"=>"",
"name"=>"personal"},
{"_id"=>"51a855763183a6301e004795",
"current"=>true,
"email"=>"xxx@gmail.com",
"name"=>"work"}]}]
Finished tests in 0.083133s, 24.0578 tests/s, 24.0578 assertions/s.
2 tests, 2 assertions, 0 failures, 0 errors, 0 skips