How do I specify which collections are being queried in AQL? - graph-databases

lets imagine I have this graph
and I want to query for all the partners connected to an user
WITH partner
FOR u IN user
FILTER u._name == #user_name
FOR v IN OUTBOUND user GRAPH 'accounts'
RETURN v
this query works when #user_name == Client because it's only connected to partners but when #user_name == Admin the profiles are returned also, when I expected an empty list (because user Admin has no partners)
Am I using the keyword WITH in the correct manner?

The purpose of the WITH keyword is to specify the collections involved in a traversal, so that they can be read-locked at query start instead of lazily during traversal, which can lead to dead lock situations. It it required for traversals in a cluster.
It does not affect the query result. If you want to return paths that end at nodes from a certain collection only, use a filter with IS_SAME_COLLECTION():
WITH user, partner, profile
FOR u IN user
FILTER u._name == #user_name
FOR v IN OUTBOUND user GRAPH 'accounts'
FILTER IS_SAME_COLLECTION('partner', v)
RETURN v

Related

How to query all association (all level) in Neo4j?

I am new to study graph databases (using Neo4j), I am modelling for my project. The business rule is that we need to store the users and devices they used, and this is my current model:
Account A uses device D: (Account A) -[USED]-> (Device D)
Account B also uses device D: (Account B) -[USED]-> (Device D)
=>
(Account A) -[USED]-> (Device D) <-[USED]- (Account B)
In future, account B will use other devices & be related with other accounts.
My questions are:
Is it a good model in this case?
With this model, how to find all associated account with account A?
Thank for you help.
Yes, this model works, as :Account and :Device nodes are distinct in the graph.
As for figuring out what other accounts that are associated with :Account a (only considering the link via using the same device), simple queries should do the trick. Assuming we have :Account(name) in the graph, and that there's an index on this (for fast lookup of :Account nodes by name), we could use this:
MATCH (:Account {name:'A'})-[:USED]->()<-[:USED]-(other:Account)
RETURN DISTINCT other
If :USED relationships always are incoming to :Device nodes, we could simplify this to:
MATCH (:Account {name:'A'})-[:USED*2]-(other:Account)
RETURN DISTINCT other
If we also needed the devices used in common between the two connected account nodes, we could include that as a collection of the nodes between the two linked accounts:
MATCH (:Account {name:'A'})-[:USED]->(device)<-[:USED]-(other:Account)
RETURN other, collect(device) as sharedDevices

AppEngine/NDB How to apply a query filter against single entity

In our app we often have several query filters that check things like archive status, permission, entity hierarchy, etc. These filters are built using NDB's operator overloads, e.g. models.Item.isArchived == False. I believe these are also referred to as FilterNode instances.
Given a set of these FilterNodes how can I apply them to a single entity that has been looked up outside of a query? Say from Memcache.
My use case is I have a predefined set of filters for an endpoint and the service allows the user to specify an entity ID. Rather than run a query, I do a get by ID. But I need to post filter to sure it's valid to return.
Found a couple of ways to do in-memory filtering using a Query object (both of these assume NDB... but can be modified for non)
this first one just uses Python builtin "filter()"... it doesn't handle sort-orders that may be in the query:
def filter_entities(query, entities):
#convert entities to list of protocol buffers
entity_pbs = [ent._to_pb() for ent in entities if ent is not None]
#assuming all entities are same type... just get type from first one
model_klass = type(entities[0])
#turn the query into a filter and hand it to builtin
filtered = filter(query.filters._to_filter(), entity_pbs)
#convert protocol buffers back into entities and hand back
return [klass._from_pb(ent) for ent in filtered if ent is not None]
This other approach uses apply_query from datastore_query... which will take sort orders into account:
from google.appengine.ext.ndb import tasklets
from google.appengine.datastore.datastore_query import apply_query
def apply_query(query, entities):
#convert list of entities to list of protocol buffers
entity_pbs = [ent._to_pb() for ent in entities if ent is not None]
#convert NDB query to datastore_query (needs connection)
conn = tasklets.get_context()._conn
dsquery = query._get_query(conn)
#call datastore_query.apply_query
filtered = apply_query(dsquery, [entity_pbs])
#convert protocol buffers back into entities and hand back
return [klass._from_pb(ent) for ent in filtered if ent is not None]
clearly I'm accessing some hidden methods that could change in the future... and so be sure you've written tests to catch that possibility

How to retrieve an Option[List[X]] instead of List[X] from a select statement in Play2!Scala Anorm?

In my Play2 app, I am trying to retrieve a list of users from one of my database table. The query responsible for this may potentially be empty if there is no row in the database matching the criteria (which is the firstName in our case). That is why I have managed to implement it like this :
DB.withConnection { implicit connection =>
SQL("""select u.* from users u
where u.firstName like '%{firstName}%'
""").on("firstName" -> firstName).as(userParser *)
}
this query returns a List[User] but how can I return an Option[List[User]] since this query may not retrieve data corresponding to the provided param (firstName) ?
any help would be appreciated
thanks...
You don't need to. If no user is found. The list will simply be empty.

CakePHP Access Allocation on Role Based specific Data Access

My project requirement is something like this:
On Top, there will be Administrator, who will have all d access, first level
Under Administrator, there will be Department Heads, who will have all d access, apart from Creating Department Heads
Under Department Head, there will Other Members, who will be managing their allocated department wise data.
Now, all different department heads will have their own information and members, and all department heads / Members will have access to their own specific records, which they are entering / managing.
Now, with CakePHP's ACL Component, I can divide the roles and their access level, but all department heads can see the other department head's information, as they will have same level of access, and All Other Members can see the other members information on diff departments, as of they will have same level of access.
My project complexity is that - they should be visible only their assigned or created information / data, though they have same level / role assignments as of others.
Can anyone suggest me best suitable option, to manage all these things with already available plug-ins with CakePHP.
I can work by customizing the default ACL Component, but that will take some more amount of time, than what is expected.
Any better ideas / suggestions would be appreciated !
the way i see it, ACL is not that magical. For exemple: ACL could manage the permissions to tell who has access to add/edit/remove a product.. but it wont be able to change a query to filter the products accordingly to the defined permissions (like "users from department A can only see products from department A").. well actually that's a lie, ACL could manage that but it might not be practical, because every time you add a product you'd have to create an ACO, and set the permission in the AROS_ACOS table and since the AROS is a tree structure, so it could easily become a nigthmare, if your planning to query your data
I'd use a group-only ACL to control the access to certain pages/actions and make rules like:
"Department Head can access the page
'products list' and add/delete/modify
products"
"Administrators can access
all pages"
"Other users can access
'products list' and they can add
products but not delete them"
and i'd adjust my queries accordingly to the connected user, so in the controller of 'products list' page, i'd do something like:
If connected user blongs to Department Head then select all products where product.department_id=connected_user.department_id
If connected user is Admin then select all products
if you have too much queries and you dont want to do thousands of if's sentences, you could create a component, a behavior or maybe extend the find() method in the app_model. The idea is to catch all queries and check if one of the models used on the query have field called "department_id", if they do then add the model.department_id=connected_user.department_id condition to the query.
I did that for one website that can be seen in multiple languages and each language has it's own users, data, logs, etc., and there's one Admin that can see all the info.. and it's working great for me =)
Good Luck!
EDITED:
the behavior i use is:
<?php
class LocalizableBehavior extends ModelBehavior {
/**
* Filter query conditions with the correct `type' field condition.
*/
function beforeFind(&$model, $query)
{
/**
* Condition for the paginators that uses joins
*/
if(isset($query['joins']) && !empty($query['joins'])){
foreach($query['joins'] as $key => $joinTable){
if(ClassRegistry::init($joinTable['alias'])->hasField('lang')){
$query['joins'][$key]['conditions'][] = $joinTable['alias'].".lang = '".$_SESSION['lang']."'";
}
}
}
/**
* condition for the normal find queries
*/
if($model->hasField('lang') && $model->name != "User"){
$query['conditions'][$model->name.'.lang'] = $_SESSION['lang'];
}
return $query;
}
}
?>
it's quite simple really, i change the query to add a condition to match to the current language ($_SESSION['lang']). In the controller all i need to do is to attach the LocalizableBehavior and use find method as usual:
$this->Products->find('all');

Running a large IN query (searching for users with an ID list) on GAE

I am trying to detect, after a user registers, which friends from Facebook have already registered for my service. My current implementation is very CPU intensive:
for eachFriend in facebookFriends:
friendUser = User.get_by_key_name(eachFriend['id'])
if friendUser:
friendUsers.append(friendUser)
I tried optimizing the query by using the IN operator:
users = User.all().filter('id IN', idList).fetch(10) # the idList is the list of IDs for a users facebook friends
This method fails as the maximum subqueries of the IN operator is 30.
Any tips?
Using an IN operator actually makes your query less efficient: Instead of doing a fast get operation for each friend, you're doing a slow query operation (IN and != filters are broken out into multiple queries on the backend).
Instead, do a single batch fetch for all the matching suers:
friendUsers = User.get_by_key_name([x['id'] for x in facebookFriends])
This returns a list of all friends, with None values for any friends that don't yet exist.
Yeah, you can have each registered user store his friends in a ListProperty so that when I register, you can do an = query on that property to see who has me as a friend. = queries on ListProperties return all entities having the filtered-on value anywhere in the list, and they don't generate subqueries the way IN queries do.
Just be aware of per-entity index limits if some of your users have tons of friends.

Resources