Добавить новый динамический атрибут с нулевым значением

#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 никогда не устанавливал вообще?