#ruby #mongodb #mongoid
#ruby #mongodb #mongoid
Вопрос:
У меня возникли проблемы с добавлением нового динамического атрибута в документ mongoid со значением nil
class User
include Mongoid::Document
include Mongoid::Timestamps
include Mongoid::Attributes::Dynamic
end
u = User.find(id)
u.write_attribute(:bar, nil)
puts u.bar
# => nil
u.save!
u = User.find(id)
puts u.bar
# => NoMethodError (undefined method `bar for #<User:0x00007fe87a97cfd8>)
Добавление нового атрибута с любым другим значением, отличным nil
от нормально работающего.
u = User.find(id)
u.write_attribute(:foo, "a")
puts u.foo
# => "a"
u.save!
u = User.find(id)
puts u.foo
# => "a"
Есть ли что-то, чего мне здесь не хватает?
Ответ №1:
Вы можете использовать #set для установки значений атрибута равными нулю. См. https://docs.mongodb.com/mongoid/master/tutorials/mongoid-persistence/#atomic .
irb(main):024:0> u.set(foo: nil)
D, [2020-10-05T21:31:20.167950 #18418] DEBUG -- : MONGODB | localhost:14400 req:15 conn:1:1 sconn:1088 | mongoid.update | STARTED | {"update"=>"users", "ordered"=>true, "updates"=>[{"q"=>{"_id"=>BSON::ObjectId('5f7bc8642c97a647f27735c6')}, "u"=>{"$set"=>{"foo"=>nil}}}], "$db"=>"mongoid", "lsid"=>{"id"=><BSON::Binary:0x7620 type=uuid data=0x606db89de7a04adf...>}}
D, [2020-10-05T21:31:20.169268 #18418] DEBUG -- : MONGODB | localhost:14400 req:15 | mongoid.update | SUCCEEDED | 0.001s
=> #<User _id: 5f7bc8642c97a647f27735c6, created_at: 2020-10-06 01:29:08.638566093 UTC, updated_at: 2020-10-06 01:29:20.656350934 UTC, bar: nil, bar1: 1, foo: nil>
Тогда #attributes работает так, как ожидалось:
irb(main):023:0> User.find(u.id).attributes
D, [2020-10-05T21:30:18.758322 #18418] DEBUG -- : MONGODB | localhost:14400 req:14 conn:1:1 sconn:1088 | mongoid.find | STARTED | {"find"=>"users", "filter"=>{"_id"=>BSON::ObjectId('5f7bc8642c97a647f27735c6'), "$and"=>[{"_id"=>BSON::ObjectId('5f7bc8642c97a647f27735c6')}]}, "$db"=>"mongoid", "lsid"=>{"id"=><BSON::Binary:0x7620 type=uuid data=0x606db89de7a04adf...>}}
D, [2020-10-05T21:30:18.759791 #18418] DEBUG -- : MONGODB | localhost:14400 req:14 | mongoid.find | SUCCEEDED | 0.001s
=> {"_id"=>BSON::ObjectId('5f7bc8642c97a647f27735c6'), "updated_at"=>2020-10-06 01:29:20.656 UTC, "created_at"=>2020-10-06 01:29:08.638 UTC, "bar1"=>1, "foo"=>nil}
Если вы считаете, что write_attribute должен сохранять атрибуты с нулевыми значениями, вы можете создать тикет по адресу https://jira.mongodb.org/browse/MONGOID описание вашего варианта использования.
Ответ №2:
Это упоминается в документах для Mongo::Attributes::Dynamic:
Если атрибут еще не существует в документе, Mongoid не предоставит вам средства получения и установки и применит обычное поведение method_missing . В этом случае вы должны использовать другие предоставленные методы доступа: ([] и []=) или (read_attribute и write_attribute).
Таким образом, вы можете просто использовать user[:bar]
или user.read_attribute(:bar)
Комментарии:
1. Я знаю об этом, но в моем примере я использую
write_attribute
для установки нового атрибута, и я ожидаю, что он будет доступен после сохранения, что неверно, когда я устанавливаю для атрибута значение nil.2. Я не слишком хорошо знаю Mongo, вы уверены, что он ведет себя так, как будто существует ключ с нулевым значением? Что происходит, когда вы просматриваете его в Mongo напрямую? Как это соотносится с поведением при поиске ключа, который wss никогда не устанавливал вообще?