Delete a node and all inbound relationships in neo4j 2.0+ - neo4jclient

First off, Neo4jClient is amazing! Thank you!
Was reading how to delete nodes and inbound relationships here but got stuck for a while:
https://github.com/Readify/Neo4jClient/wiki/cypher-examples#delete-a-user-and-all-inbound-relationships
graphClient.Cypher
.Match("(user:User)<-[?:r]-()")
.Where((User user) => user.Id == 123)
.Delete("r, user")
.ExecuteWithoutResults();
Anytime i tried executing the code above, i'd always get an error of "?" has been depreciated and use an alternate Cypher query.

After some investigating, i found the following works:
graphClient.Cypher
.OptionalMatch("(user:User)<-[r]-()")
.Where((User user) => user.Id == 123)
.Delete("r, user")
.ExecuteWithoutResults();
You will see the notice in the above code block that we exchange Match for OptionalMatch and remove the "?" by the relationship.
This could be an answer so i marked as a answer however, is this the correct way to do this now and the Neo4jClient (v.645) has not been updated yet to reflect the deprecation? Or am i doing something wrong? Or does this method create unintended consequences with larger data sets and more relationships on each now?
Thanks!

Related

Why is TypeORM returning no records in this simple query?

I'm trying to get all the users on my system that match a complex where conditional with TypeORM. My end query would look something like this:
connection.createQueryBuilder()
.select().from(User, "user")
.where("email IS NULL OR email NOT LIKE '%#example.com'")
.getMany()
If I run that query with getCount() it works and tells me how many I have, but getMany() return []
In fact, I simplified it to this:
console.log(
await connection.createQueryBuilder()
.select().from(User, "user")
.getManyAndCount())
I get this surprising result (with logging enabled):
query: SELECT * FROM "user" "user"
query: SELECT COUNT(DISTINCT("user"."id")) as "cnt" FROM "user" "user"
[ [], 14 ]
Any ideas why I would get no users when the count shows 14? I run the query manually and it obviously shows the users... what's going on here?
The code that Carlo offered in one of the answers:
await connection.getRepository(User).findAndCount()
works, but that won't let me have my where clause (as far as I know, I'm still new to TypeORM). I'm just sharing this to show that the User model seems to be working fine, except when I use it with the query builder to select a bunch of users (counting and deleting works).
Keep your code syntax as simple as possible since TypeORM docs (now) are't perfect.
Try using Find Options since I can't find any getManyAndCount() method for QueryBuilder:
const users = await connection
.getRepository(User)
.findAndCount();
EDIT:
Of course you can have (complex) where clause with find.
You can chain multiple where clauses (OR) with a really simple syntax. Check out all options here.
Example that map your "raw" query:
const users = await connection
.getRepository(User)
.findAndCount({
where: [
{
email: IsNull(),
},
{
email: Not(Like('%#example.com')),
},
],
});
Hope it helps :)
Let me divide that step-by-step approach
despite of getManyAndCount() use getRawEntities()
you will get the data for sure by using 1st point
now concentrate on the keys you are getting on data
use the same key on your select query and done
if you didn't get records using getRawEntities():
I. try to use select * i.e, select()
II. check the column name and correct that
Additionally, It can also depend on your entity structure. Carefully check that too.

Rails can't select where foreign key is nil

I have a rails app with a Customer and a ShippingAddress model. It is implemented with a one-to-many relationship so that a ShippingAddress can have multiple customers.
I am successfully able to query across these two models and several others with an include statement, but as I tried to update the query to find all of the customers that does not have a shipping_address got 0 results, even though I am able to se from my DB-admin tool that I have multiple customers where the value of the shipping_address_id is nil.
These queries works, but does not give me customers without addresses:
Customer.includes(:orders, :shipping_address).where('customers.name LIKE ? or customers.mail LIKE ?', searchstring, searchstring)
Customer.where('customers.shipping_address_id = ?',2)
These attempts to adapt the above to give me customers without addreses doesn't:
Customer.includes(:orders, :shipping_address).where('shipping_address = ?', nil)
Customer.includes(:orders, :shipping_address).where('shipping_address = NULL')
# At the very least I should be able to get the right result by referencing the fk directly, but no?
Customer.where('customers.shipping_address_id = ?',nil)
What am I missing here?
The NULL value can be surprising until you get used to it. Conceptually, NULL means “a missing unknown value” and it is treated somewhat differently from other values.
You cannot compare null using equal to for this you must use IS NULL. So update your queries to
Customer.includes(:orders, :shipping_address).where('customers.shipping_address_id IS NULL')
Or rails way of doing this is
Customer.where(shipping_address_id: nil).includes(:orders, :shipping_address)
You could also just do:
#customers_without_shipping_ids = Customer.where('shipping_address_id IS NULL').all
Please have a try with these queries
Customer.all(:conditions => ['shipping_address_id IS NULL'])
and
Customer.includes(:orders, :shipping_address).where('shipping_address_id IS NULL')

Rails find where ALL associated records meet condition

I'm trying to get all the clients that have doctors associated BUT none of them has started their first session (one client has_many doctors and can have first sessions with each of them).
So far I have:
#clients = Client.joins(:doctors).where('doctors.first_session IS NULL').order('clients.id DESC')
But this doesn't work when a client has for example 2 doctors. the first doctor.first_session = null but the second one is not. This case will return the client and it don't want it to.
Any ideas?
This is one of those cases where in order to find records that don't meet a certain condition, you do it by finding all records except those that meet the condition. In SQL this is done with a subquery in the WHERE clause.
For cases like this, the squeel gem is extremely helpful, because it encapsulates the SQL complexity. This is how I would do it (with squeel):
scope :visited_doctor, joins(:doctors).where { doctors.first_visit != nil }
scope :not_visited_doctor, where { id.not_in(Patient.visited_doctor.select(:id)) }
Note that you can do this without squeel, but you'll have to get your hands (and your code) dirty with SQL.
This will work, but may be a little less efficient since it does some of the work in ruby instead of all in the db.
clients = Client.order('clients.id DESC').include(:doctors).select do |client|
client.doctors.all? {|doctor| doctor.first_session.nil? }
end
Logically, that should fetch all the clients, and then in ruby, the select will evaluate the condition in the block and those clients that return true will be assigned to clients.
The condition block will return true only if all of that client's doctors have a nil first_session.
Hope that helps. There's probably a more efficient way to do this using subselects, but the syntax for that is likely to depend on which database you're using.
Well, I found a solution that involved two queries.
avoid_ids_results = Doctors.select('client_id')
.where("first_session IS NOT NULL")
.map(&:client_id).join(', ')
#clients = Clients.
joins(:doctors).
where('clients.id NOT IN (' + avoid_ids_results + ')').
order('clients.id DESC')
Thank you all!
You could create a method in your Client model which returns true if any first_session on a client's doctors is true, something like...
def has_first?
self.doctors.each do |doctor|
return true if !doctor.first_session.nil?
end
return false
end
This is pseudocode and may need to be tweaked first

Mongoid OR query syntax

This must be asked alot but it is very poorly documented. There is no mention at http://mongoid.org/en/mongoid/docs/querying.html
I'm trying to check whether a user exists (below is an AND query), how can I change it to an OR type query
Username.where(:username=>#username, :email=>#email)
(Either the email or the username must match).
I have found some pretty complicated ways online including sending a direct javascript (from): http://omarqureshi.net/articles/2010-6-17-using-or-in-mongoid
Surely there must be a simple clear syntax to do this correctly?
For the sake of others who end up on this page, the updated syntax is now
Username.or({username: #username}, {email: #email})
Please refer to the updated docs or relevant impl.
Yeah, this used to be documented better. Try this:
Username.any_of({:username => #username},
{:email => #email})
There is a typo in #miguel-savignano's response. According to Stackoverflow the "edit queue is full", which is why I didn't submit an edit.
Proper syntax:
Username.or({username: #username}).or({email: #email})
A more concise solution:
Username.or({username: #username}, {email: #email})
The Mongo selector will resolve to:
{"$or"=>[{"username"=>#username}, {"email"=>#email}]}
I found this question as I was trying to solve for creating "or" queries.
If you are looking to match a string or any one of an array of elements, then you will need to write a Mongoid query with the Mongo '$in' selector.
For example, you have a specific username and an array of emails. You would like to return all results where at least one of the fields matches either the username or one of the emails within the array.
#username = "jess"
#emails = ["hi#mail.com", "test#mail.com", "foo#mail.com"]
User.or({username: ""}, {email: {'$in': #emails}})
The Mongo selector will resolve to:
{"$or"=>[{"first_name"=>""}, {"email"=>{:$in=>["hi#mail.com", "test#mail.com", "foo#mail.com"]}}]}
If you have Users with 2 of the 3 emails in your database, then the selector will return a count of 2.
If you have a User with the username "jess" and 3 additional Users each with one of the given emails, then the selector will return a count of 4.
Also, in Mongoid 5.0, if you still want to use the where method, use the following
Username.where('$or' => [ { username: #username }, { email: #email } ])
this is very useful when you are building a kind of query hash in a dynamic way and you need to keep the where method
In Mongoid 5.0, this works for me
Username.or({username: #username}).or({email: #email})

Remove a 'where' clause from an ActiveRecord::Relation

I have a class method on User, that returns applies a complicated select / join / order / limit to User, and returns the relation. It also applies a where(:admin => true) clause. Is it possible to remove this one particular where statement, if I have that relation object with me?
Something like
User.complex_stuff.without_where(:admin => true)
I know this is an old question, but since rails 4 now you can do this
User.complex_stuff.unscope(where: :admin)
This will remove the where admin part of the query, if you want to unscope the whole where part unconditinoally
User.complex_stuff.unscope(:where)
ps: thanks to #Samuel for pointing out my mistake
I haven't found a way to do this. The best solution is probably to restructure your existing complex_stuff method.
First, create a new method complex_stuff_without_admin that does everything complex_stuff does except for adding the where(:admin => true). Then rewrite the complex_stuff method to call User.complex_stuff_without_admin.where(:admin => true).
Basically, just approach it from the opposite side. Add where needed, rather than taking away where not needed.
This is an old question and this doesn't answer the question per say but rewhere is a thing that exists.
From the documentation:
Allows you to change a previously set where condition for a given attribute, instead of appending to that condition.
So something like:
Person.where(name: "John Smith", status: "live").rewhere(name: "DickieBoy")
Will output:
SELECT `people`.* FROM `people` WHERE `people`.`name` = 'DickieBoy' AND `people`.`status` = 'live';
The key point being that the name column has been overwritten, but the status column has stayed.
You could do something like this (where_values holds each where query; you'd have to tweak the SQL to match the exact output of :admin => true on your system). Keep in mind this will only work if you haven't actually executed the query yet (i.e. you haven't called .all on it, or used its results in a view):
#users = User.complex_stuff
#users.where_values.delete_if { |query| query.to_sql == "\"users\".\"admin\" = 't'" }
However, I'd strongly recommend using Emily's answer of restructuring the complex_stuff method instead.
I needed to do this (Remove a 'where' clause from an ActiveRecord::Relation which was being created by a scope) while joining two scopes, and did it like this: self.scope(from,to).values[:joins].
I wanted to join values from the two scopes that made up the 'joined_scope' without the 'where' clauses, so that I could add altered 'where' clauses separately (altered to use 'OR' instead of 'AND').
For me, this went in the joined scope, like so:
scope :joined_scope, -> (from, to) {
joins(self.first_scope(from,to).values[:joins])
.joins(self.other_scope(from,to).values[:joins])
.where(first_scope(from,to).ast.cores.last.wheres.inject{|ws, w| (ws &&= ws.and(w)) || w}
.or(other_scope(from,to).ast.cores.last.wheres.last))
}
Hope that helps someone

Resources