List Dynamic Attributes in a Mongoid Model

List dynamic attributes in a Mongoid Model

Just include something like this in your model:

module DynamicAttributeSupport

def self.included(base)
base.send :include, InstanceMethods
end

module InstanceMethods
def dynamic_attributes
attributes.keys - _protected_attributes[:default].to_a - fields.keys
end

def static_attributes
fields.keys - dynamic_attributes
end
end

end

and here is a spec to go with it:

require 'spec_helper'

describe "dynamic attributes" do

class DynamicAttributeModel
include Mongoid::Document
include DynamicAttributeSupport
field :defined_field, type: String
end

it "provides dynamic_attribute helper" do
d = DynamicAttributeModel.new(age: 45, defined_field: 'George')
d.dynamic_attributes.should == ['age']
end

it "has static attributes" do
d = DynamicAttributeModel.new(foo: 'bar')
d.static_attributes.should include('defined_field')
d.static_attributes.should_not include('foo')
end

it "allows creation with dynamic attributes" do
d = DynamicAttributeModel.create(age: 99, blood_type: 'A')
d = DynamicAttributeModel.find(d.id)
d.age.should == 99
d.blood_type.should == 'A'
d.dynamic_attributes.should == ['age', 'blood_type']
end
end

Dynamic attributes with Rails and Mongoid

Mongoid doesn't really support it.

I happen to have asked this at Mongoid group myself.

It is possible when you create new document, like this:

account = Account.new(:some_dynamic_field => "...")

Add new dynamic attribute with nil value

You can use #set to set attribute values to nil. See 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>

Then #attributes works as expected:

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}

If you believe write_attribute should persist attributes with nil values, you can create a ticket at https://jira.mongodb.org/browse/MONGOID describing your use case.

how to create dynamic attributes for different data types and store in mongodb

I don't understand exactly why your solution doesn't work. Try next:

Specify some class with your attributes:

import java.util.Map;
import org.springframework.data.mongodb.core.mapping.Document;

@Document
public class User {
private Map<String, Object> attributes;

public User(Map<String, Object> attributes) {
this.attributes = attributes;
}

public Object getAttribute() {
return this.attributes;
}}

Specify mongodb repository:

interface UserRepository extends MongoRepository<User, UUID> {}

Controller to save dummy User:

@RestController
public class DemoController {

@Autowired
UserRepository userRepository;

@GetMapping("/save")
public User doSave() {
Map<String, Object> attributes = new HashMap<>();

attributes.put("time", Instant.now());
attributes.put("num", 5.6);
attributes.put("str", "5.6");

return userRepository.save(new User(attributes));
}
}

I got the next response:

{
"attribute": {
"str": "5.6",
"num": 5.6,
"time": "2019-07-24T12:22:07.390Z"
}
}

The object in MongoDB:

Sample Image



Related Topics



Leave a reply



Submit