Running native mongodb commands in rails - ruby-on-rails

I'm using Mongoid, but all I need to do is increment a field which is an integer. Would it be worth it for me to skip using Mongoid's methods, and just run the mongodb ruby drivers method to increment a value?
How would I do that?

Mu is too short is correct, you could either use the built in mongoid #inc method:
Model.inc(:field, integer)
Or you could access the collection directly via the collection attribute:
Model.collection.update(
{ query document },
{ "$inc" => { :field => value } }
)

Why not use Mongoid's inc method?
Model#inc
Performs MongoDB's $inc modifier which increments it's value by the supplied amount or initializes it to that value. If the field is not numeric an error will be raised.
So doing model.inc(:a, 11) should send an { $inc: { a: 11 } } update straight into MongoDB.

Related

How do I query a WhereChain in Rails 6?

I’m upgrading from Rails 4.2 to Rails 6. I have this scope in a model …
scope :valid_type, -> { where{ (model_type == nil) | (modeltype << [36, 38]) } }
Previously, I could run this
MyModel.valid_type.include?(model_instance)
But now I get
NoMethodError:
undefined method `include?' for #<ActiveRecord::QueryMethods::WhereChain:0x00007fb9fc58b3e0>
What’s the right way in Rails 6 to check for inclusion in a WhereChain?
You are currently passing a block to where. where does not accept a block neither in 4.2 or 6.0
The block parameter is being ignored. Since you're not passing an argument to where, it's being treated as a WhereChain that only has one method on it: not. For example as a part of where.not(my_column: nil)
You'll need to fix your syntax. Use the .or method to join your queries and use proper ActiveRecord syntax.
scope :valid_type, -> { where(model_type: nil).or(where(modeltype: [36, 38])) }
In your current case though, Rails will handle the nil for you so there is no need for the or
scope :valid_type, -> { where(modeltype: [nil, 36, 38]) }

What is nodeInterface, nodeField and nodeDefinitions in Relay?

I am currently doing the facebook relayjs tutorial and I need help understanding this part of the tutorial, it states
Next, let's define a node interface and type. We need only provide a
way for Relay to map from an object to the GraphQL type associated
with that object, and from a global ID to the object it points to
const {nodeInterface, nodeField} = nodeDefinitions(
(globalId) => {
const {type, id} = fromGlobalId(globalId);
if (type === 'Game') {
return getGame(id);
} else if (type === 'HidingSpot') {
return getHidingSpot(id);
} else {
return null;
}
},
(obj) => {
if (obj instanceof Game) {
return gameType;
} else if (obj instanceof HidingSpot) {
return hidingSpotType;
} else {
return null;
}
}
);
On the first argument on nodeDefinition,where did it get its' globalId? is Game and HidingSpot a name on the GraphQLSchema? What does this 'const {type, id} = fromGlobalId(globalId);' do? and also what is the 2nd argument? I need help understanding nodeDefinitions, somehow I can't find nodeDefinitions on the official documentation. Thank you.
If you were writing a GraphQL server without Relay, you'd define a number of entry points on the Query type, eg:
type Query {
picture(id: Int!): Picture
user(id: Int!): User
...etc
}
So when you want to get a User, you can easily get it because user is available as an entry point into the graph. When you build a query for your page/screen, it'll typically be several levels deep, you might go user -> followers -> pictures.
Sometimes you want to be able to refetch only part of your query, perhaps you're paginating over a connection, or you've run a mutation. What Relay's Node interface does is give you a standard way to fetch any type that implements it via a globally unique ID. Relay is capable of recognising such nodes in its queries, and will use them if possible to make refetching and paginating more efficient. We add the node type to the root Query type:
type Query {
picture(id: Int!): Picture
user(id: Int!): User
...etc
node(id: ID!): Node
}
Now for nodeDefinitions. Essentially this function lets us define two things:
How to return an object given its globalId.
How to return a type given an object.
The first is used to take the ID argument of the node field and use it to resolve an object. The second allows your GraphQL server to work out which type of object was returned - this is necessary in order for us to be able to define fragments on specific types when querying node, so that we can actually get the data we want. Without this, we couldn't be able to successfully execute a query such as this:
query Test {
node(id: 'something') {
...fragment on Picture {
url
}
...fragment on User {
username
}
}
}
Relay uses global object identification, which means, in my understanding, if your application ever try to search for an object. In your example, try to look for a game, or try to look for a hidingSpot. Relay will try to fetches objects in the standard node interface. i.e. find by {id: 123} of the Game, or find by {id:abc} of the hidingSpot. If your schema (Game, HidingSpot) doesn't set up the node interface, Relay will not be able to fetch an object.
Therefore, if your application requires a search in a "Game", in the schema, you need to define the node interfaces.
By using graphql-relay helper, use nodeDefinitions function only once in your application to basically map globally defined Ids into actual data objects and their GraphQL types.
The first argument receives the globalId, we map the globalId into its corresponding data object. And the globalId can actually be used to read the type of the object using fromGlobalId function.
The second function receives the result object and Relay uses that to map an object to its GraphQL data type. So if the object is an instance of Game, it will return gameType, etc.
Hope it will help you understand. I am on my way learning, too.

Arrays in Ruby: Take vs Limit vs First

Suppose you have an array of objects in Rails #objects
If I want to display the first 5 objects, what is the difference between using:
#objects.limit(5)
#objects.take(5)
#objects.first(5)
I am talking about the front end (Ruby), NOT SQL. The reason why the objects are not limited in SQL is because the same array may be used elsewhere without applying a limit to it.
Does it have anything to do with object instantiation?
limit is not an array method
take requires an argument; it returns an empty array if the array is empty.
first can be called without an argument; it returns nil if the array is empty and the argument is absent.
Source for 2.0 take
static VALUE
rb_ary_take(VALUE obj, VALUE n)
{
long len = NUM2LONG(n);
if (len < 0) {
rb_raise(rb_eArgError, "attempt to take negative size");
}
return rb_ary_subseq(obj, 0, len);
}
Source for 2.0 first:
static VALUE
rb_ary_first(int argc, VALUE *argv, VALUE ary)
{
if (argc == 0) {
if (RARRAY_LEN(ary) == 0) return Qnil;
return RARRAY_PTR(ary)[0];
}
else {
return ary_take_first_or_last(argc, argv, ary, ARY_TAKE_FIRST);
}
}
In terms of Rails:
limit(5) will add the scope of limit(5) to an ActiveRecord::Relation. It can not be called on an array, so limit(5).limit(4) will fail.
first(5) will add the scope of limit(5) to an ActiveRecord::Relation. It can also be called on an array so .first(4).first(3) will be the same as .limit(4).first(3).
take(5) will run the query in the current scope, build all the objects and return the first 5. It only works on arrays, so Model.take(5) will not work, though the other two will work.
The answer chosen answer seems to be outdated (in terms of Rails) so I would like to update some information.
limit on an ActiveRecord::Relation will still be a Relation. So if you call:
Model.limit(5).limit(4)
will be same as:
Model.limit(4)
first on an ActiveRecord::Relation will make the result an Array. So you cannot call any scope after first like:
Model.first(5).where(id: 1)
But you can do this:
Model.limit(5).where(id: 1)
take
Model.take(5)
works now. It will return an array, so you cannot call any scope either.
On an ActiveRecord::Relation object, if you call first it will include ORDER BY 'tables'.id. Whereas with limit and take there is no ORDER BY included but the sorting is depended by the database sorting implementation.

ConcurrencyCheck/Datatype

In breeze.debug.js:
function updateConcurrencyProperty(entity, property) {
...
else if (property.datatype === DataType.Binary) {
// best guess - that this is a timestamp column and is computed on the server during save
// - so no need to set it here.
return;
} else {
// this just leaves DataTypes of Boolean, String and Byte - none of which should be the
// type for a concurrency column.
// NOTE: thought about just returning here but would rather be safe for now.
throw new Error("Unable to update the value of concurrency property before saving: " + property.name);
}
i have a timestamp on my models. Why is this not recommended? An EF Tutorial on ASP.Net uses the timestamp.
What would you recommend as Concurrencycheck column?
Not sure where we say it's not recommended; the only issue is that its not terribly portable across databases, SQLServer 'timestamp' columns are not actually time based, ... but they should still work as concurrency columns with breeze. If not, its likely a bug.
For more info: datetime or timestamp
There was a bug involving SQL Server Timestamp columns that is now fixed in v 0.76.4. ... Thanks for finding this, Sascha.

Strange behavior of gorm finder

In a controller I have this finder
User.findByEmail('test#test.com')
And works.
Works even if I write
User.findByEmail(null)
But if i write
User.findByEmail(session.email)
and session.email is not defined (ergo is null) it throw exception
groovy.lang.MissingMethodException: No signature of method: myapp.User.findByEmail() is applicable for argument types: () values: []
Is this behavior right?
If i evaluate "session.email" it give me null so I think it must work as it do when I write
User.findByEmail(null)
Even more strange....
If I run this code in groovy console:
import myapp.User
User.findByEmail(null)
It return a user that has null email but if I run the same code a second time it return
groovy.lang.MissingMethodException: No signature of method: myapp.User.findByEmail() is applicable for argument types: () values: []
You can't use standard findBySomething dynamic finders to search for null values, you need to use the findBySomethingIsNull version instead. Try
def user = (session.email ? User.findByEmail(session.email)
: User.findByEmailIsNull())
Note that even if User.findByEmail(null) worked correctly every time, it would not necessarily give you the correct results on all databases as a findBySomething(null) would translate to
WHERE something = null
in the underlying SQL query, and according to the SQL spec null is not equal to anything else (not even to null). You have to use something is null in SQL to match null values, which is what findBySomethingIsNull() translates to.
You could write a static utility method in the User class to gather this check into one place
public static User byOptEmail(val) {
if(val == null) {
return User.findByEmailIsNull()
}
User.findByEmail(val)
}
and then use User.byOptEmail(session.email) in your controllers.
Jeff Brown from grails nabble forum has identified my problem. It's a GORM bug. see jira
More info on this thread
This jira too
I tried with debugger and it looks it should be working, as you write. Maybe the groovy itself is a little bit confused here, try to help it this way:
User.findByEmail( session['email'] )

Resources