Mongoid add field but don't exist in mongodb - mongodb

I use Mongoid to query db in a rails project.
When i add a field "scope" to a User Model
class User
include Mongoid::Document
field :scope, type: String
end
When use rails console, we can find this field have add to User model.
But when we go to mongodb console to view users data, use db.users.find(), it don't have scope field yet.
also when i want update scope field in rails console. It always have below error.
pry(main)> user = User.first
=> #<User _id: 521dcd4464fad29a74000009, scope: "private", xxx_id: "521dcd4464fad29a74000008">
pry(main)> user.update_attributes(scope: "public")
Moped::Errors::OperationFailure: The operation: #<Moped::Protocol::Command
#length=84
#request_id=17
#response_to=0
#op_code=2004
#flags=[]
#full_collection_name="blog_development.$cmd"
#skip=0
#limit=-1
#selector={:getlasterror=>1, :safe=>true}
#fields=nil>
failed with error 11000: "E11000 duplicate key error index: blog_development.users.$_id_ dup key: { : ObjectId('521dcd4464fad29a74000009') }"
Any one can tell me why?

Just adding field :scope, type: String to your model won't add it to the underlying MongoDB collection, that just tells Mongoid that it should allow the model to have a scope for accessors, mutators, validations, mass-assignment, ... Keep in mind that different documents in a MongoDB collection can have entirely different properties so the schema is really a fiction that is applied by Mongoid.
If you want all your users to have a scope then you'd have to say something like this:
User.collection.find().update_all(:$set => { :scope => 'whatever it should be' })
to manually add it to all the documents.

The field exists in your saved objects. But to be able to find one with your asked value, you have to create one.
class User
include Mongoid::Document
field :name, type: String
field :age, type: Integer
end
User.find(name: 'John')
# => nil
User.create({ name: 'John', age: '18' })
# => User 284692 :name => 'John', :age => 18
User.find(name: 'John')
# => User 284692 :name => 'John', :age => 18
Hope it helps.
edit after 'mu is too short' post :
To fill all existing objects in db, just provide a :default value to your field
class User
field :name, type: String, default: 'Martin Dupont'
end

Thanks for reply.
The reason is in this model, i have overwrite new_record? method. So cause this error.

Related

Does Gatsby support MongoDB relationships?

I am building a personal blog and chose Gatsby because of the obvious reasons(performance and easy to start out) and because I have some React background for the frontend. Also, I had built a simple app to create my content(html string) and store in a MongoDB database using express server. Now for the blog, I am just trying to pull the data from MongoDB using gatsby-source-mongodb plugin.
My MongoDB schemas have relationships. For instance, a 'Post' schema has a 'user' property which is an ObjectID that references a user from 'User' schema. My config for the gatsby-source-mongodb looks like:
{
resolve: 'gatsby-source-mongodb',
options: {
dbName: 'KathaDB',
collection: 'posts',
server: {
address: "somecluster",
port: 27017
},
auth: {
user: 'someuser',
password: 'somepasswd'
},
extraParams: {
replicaSet: 'test',
ssl: true,
authSource: 'admin',
retryWrites: true,
preserveObjectIds: true
}
}
}
I have a couple of questions:
When I query, I get all the properties from my 'Post' schema but I don't have 'user' property in the response. I don't know if it is due to the type of the property. I dug up a bit and found a similar issue here. It seems like they have solved the issue by preserving the ObjectID but i didn't even get the property that is of type ObjectID.
Another thing, does this plugin support relationships? For example, is it possible to get the 'user' data when its ObjectID is given?
It does.
MongoDB relies on ObjectIDs for relationships, so you might have to add preserveObjectIds: true to your plugin options:
{
resolve: "gatsby-source-mongodb",
options: {
dbName: "KathaDB",
collection: "posts",
server: {
address: "somecluster",
port: 27017,
},
auth: {
user: "someuser",
password: "somepasswd",
},
extraParams: {
replicaSet: "test",
ssl: true,
authSource: "admin",
retryWrites: true,
preserveObjectIds: true,
},
preserveObjectIds: true, // <= here
},
};
I'm unsure whether gatsby-source-mongodb creates the relationships out of the box (I don't think it does, if my memory is correct), but with the ObjectIds, you can create foreign-key relationships using GraphQL.
There are two ways of doing this in Gatsby:
Using mappings in gatsby-config.js
Using a GraphQL #link directive through Gatsby's schema customization (from v2.2)
I recommend the second option, since it's a more GraphQL way of doing things, and happens in gatsby-node.js where most node operations are taking place. However, if you're starting out with Gatsby and GraphQL, the first option might be easier to set up.

Correct way to do a PATCH upsert request

What is the proper way to request the following upsert to a REST API?
I'm struggling to structure a NoSQL collection, which is based on the most requested returns to the front-end application.
Suppose you have the following document:
{
'user' : {
'private_comments': [
//object available only to user 1
{
'id': 1,
'bar': 'He is very good',
'...': '...'
},
//object available only to user 2
{
'id': 2,
'bar': 'He is very bad',
'...': '...'
}
],
'public_comments': '' //infos available to all users
}
}
It is needed to upsert an element to the user.private_comments array.
According to https://www.rfc-editor.org/rfc/rfc6902#appendix-A.5, I could request a replace instruction PATCHing the following data:
{ 'op': 'replace', 'path': '/user/comments/$index', 'value': 'Actually, he is OK'}
The problem is that '$index' is unknown in this case.
A possible solution that I came up with was to create something like the following operation:
{ 'op': 'upsert', 'find_by': 'id', 'find': 1, 'path': '/user/comments', 'value': 'Nope, he really sucks' }
However, the user implementing the API should't provide the id value inside the PATCH request, because this value is already accessible via the receive token. Should I simplify the operation to:
{ 'op': 'upsert', 'path': '/user/comments', 'value': 'Nope, he really sucks' }
and treat it at the backend, so when it's and upsert operation without 'find' and 'find_by' variables I assume 'find_by': 'id' and 'find': value_from_token?
Also, I cannot do a simple GET/UPDATE at the hole document because the user doesn't receive the hole document, so an update would compromise the data.

Is it possible to create indexes in Mongodb for dynamic fields?

My site has several "domains" which represent sub-sections of the site. Each "domain" has its own users with profiles, and a search page where you can search for users based on profile fields that the users fill out.
User data from the 'users' collection is structured like so:
{
username: 'shawnmichaels',
first_name: 'Shawn',
last_name: 'Michaels',
domains: [
{
name: 'domain1',
user_fields: {
'bio': 'Short bio related to domain 1',
'skills': 'Pertinent skills for domain 1'
}
},
{
name: 'domain2',
user_fields: {
'bio': 'Short bio related to domain 2',
'skills': 'Pertinent skills for domain 2'
}
}
]
}
So, users have field data across multiple domains. The domain names and field names are dynamic. There could potentially be hundreds of domains for a user and dozens of fields in a domain.
Is it possible to have some sort of dynamic index so that I can search for fields under 'domain1' without getting any matches in 'domain2'?
For example, if a user1 has "skills": ["karate", "judo"] under 'domain1', and I want to search domain2 for "karate", I don't want a match for user1.
For anyone interested, I've answered my own question after a day of research.
I'm pretty new to MongoDB and didn't realize you can query arrays by treating them like any other keys, like so:
db.users.find({domains.title: 'domain1'})
// where 'domains' is an array of object each with a 'title' key
With this knowledge, I added a text index for each field I want to be searchable:
db.users.ensureIndex({
'username': 'text',
'first_name': 'text',
'last_name': 'text',
'domains.fields.bio': 'text',
'domains.fields.skills': 'text',
'domains.fields.title': 'text',
'domains.fields.training': 'text'
}, {name: 'domain_search'})
And I structured search queries in each domain like so:
db.users.find({
'domains.title': DOMAIN_NAME,
'$text': {'$search': SEARCH_TERM}
})

Symfony2 overriding bundle HTML form input constraints

I am trying to override FOSUserBundle's max username length. Seems simple enough but I can't manage to do it.
validation.yml
AppBundle\Entity\User:
properties:
username:
- Length: { max: 5, groups: [CustomRegistration] }
config.yml
fos_user:
[...]
user_class: AppBundle\Entity\User
registration:
form:
validation_groups: [CustomRegistration]
Validation itself works fine. If user provides username longer than 5 characters Symfony shows an error that it should not be longer than 5 characters. The problem is that the HTML form input still uses default FOSUserBundle value (255). Form builder seems to totally ignore validation groups. Is there any way I can tell form builder to use my constraints?
I want to mention that HTML validation works when I use XML format but I need to use YAML and it works only by coincidence so I would not like to rely on such quirk.
I also tried to provide custom type in hope that it will change anything but it didn't. Username input still uses maxlength value of 255. For reference:
getDefaultOptions # AppBundle/Form/RegistrationFormType.php
public function getDefaultOptions(array $options)
{
return [
'data_class' => 'AppBundle\Entity\User',
'validation_groups' => ['Default', 'CustomRegistration']
];
}
config.yml
fos_user:
[...]
user_class: AppBundle\Entity\User
registration:
form:
type: appbundle_registration
services.yml
services:
appbundle.registration.form.type:
class: AppBundle\Form\RegistrationFormType
tags:
- { name: form.type, alias: appbundle_registration }
You should add max-length HTML attribute manually to the field.
Validation has no effect on HTML attributes.
buildForm # AppBundle\Form\RegistrationFormType
$builder->add("username", "text", array("attr" => array("maxlength" => "5")));
See: http://symfony.com/doc/current/reference/forms/types/text.html#max-length
If it doesnt solve the issue, take a look at your template. It can be setted there too..

SugarCRM Rest API: Required fields for a Meeting entry?

I'm trying to create a Meeting entry via the API, but I can't seem to find it in my calendar even though it saved successfully (I got the ID back) and I can see it in the Meetings list.
What fields do I need to populate for it to show in my Sugar calendar? Here are the fields I'm populating:
{
'assigned_user_id': '1', # My user's ID
'date_end': '2013-04-16 01:30:00',
'date_start': '2013-04-16 01:23:45',
'description': 'hello world',
'location': 'JCenter',
'name': 'Test',
'team_id': '1',
'type': 'Sugar' # This doesn't seem to be required
}
Try to set "user_id" and take a look into mettings_users table where you will find it.