Create edge from attribute with ArangoDB AQL - arangodb

I have imported a list of documents (in a collection named "assemblies"). One of the attributes is "parent_id".
Based on this, I want to construct the graph, that is implicitly described by this attribute.
"id","name","parent_id"
"30","Top level"
"30.1","30.1 Child 1","30"
"30.2","30.2 Child 2","30"
This is the query, that I expected to give me the info for creating the edge collection (named "contains", so it is from parent to child):
FOR assy IN assemblies
LET parent = (
FOR parent IN assemblies
FILTER parent.id == assy.parent_id
RETURN parent
)
RETURN {_from: parent._key, _to: assy._key}
What am I doing wrong? Could you give me the full query for inserting the edges?

The problem is that the result of your subquery in parent is an array and not an document. But there is actually no need of a subquery. You can also performe a join, which should offer better performance and is easier to read.
You also have to use the value of _id insteadt of _key for the fields _from and _to of your edges.
The following query does exactly what you want.
FOR assy IN assemblies
FOR parent IN assemblies
FILTER parent.id == assy.parent_id
INSERT {_from: parent._id, _to: assy._id} IN contains
RETURN NEW
Node: the RETURN NEW is optional. You can check with it whether the import was successful. With larger amount of data I would drop this.

Related

Manipulating value from complex query in Neo4j

I am new to Neo4j DB and I have a Neo4j DB with the following nodes,
Attribute
Entity1
Entity2 - has relation with children as label CHILD
Entity2-1
Entity2-2
...
Entity2-n
And all entities may have relation with others which has label VALUE and property value.
Relationships:
Entity2 -> Attribute
Entity2-n -> Attribute
Entity2 -> Entity1
Entity2-n -> Entity1
Entity1 -> Attribute
I need to fetch these node's relation values and if entity has no direct value then need to fetch it's parent entity value.
For example, if entity2-2has no relation with Attribute, then need to check if it's parent entity2 has relation with value, if not get the Attribute node value.
For this, I am trying this query, but not working as expected and getting empty values
MATCH (a:ATTRIBUTE {name: 'test' })
match (e1:ENTITY1 {id:'c0f333ca-a9cc-4c09-ac30-7c460512f1f9' })
optional match ((e1)-[entity1GlobalValue:VALUE {id:a.id}]->(a))
optional match ((e2:ENTITY2 {id: 'c47004cc-3f48-51fd-9a38-69274341e344'})-[:CHILD]->(e2Children:ENTITY2))
optional match ((e2Children)<-[:CHILD*]-(e2Parent:ENTITY2))
optional match ((e2Children)<-[e2ChildrenE1Values:VALUE {id:a.id}]-(e1))
optional match ((e2Parent)<-[e2ParentE1Values:VALUE {id:a.id}]-(e1))
optional match ((e2Children)<-[e2ChildrenGlobalValues:VALUE {id:a.id}]-(a))
optional match ((e2Parent)<-[e2ParentGlobalValues:VALUE {id:a.id}]-(a))
RETURN a, e1, entity1GlobalValue, e2Children, e2ChildrenE1Values, e2ParentE1Values, e2ChildrenGlobalValues, e2ParentGlobalValues;
Not sure what is the mistake here?
Is my query effiecent ? There is Unique constraint on id field.
Update:
Rough diagram:
Here I am looking for value which is stored in the relations between Nodes.
Entity2 has children Entity2-1 and Entity2-2, where I have to find the value for these children with other entities - Entity1 and Attribute.
Thanks
Based on the graph provided I understand that you have to get the values for the child nodes which has relationship VALUE. If that's the case find the below query.
MATCH (n:Entity2)-[:CHILD]->(c)
with collect(c)+n as childNodes
UNWIND childNodes as cNode
MATCH (cNode)-[v:VALUE]->(endNode)
RETURN
labels(cNode) as fromNode,
v.value as value,
labels(endNode) as toNode
The result would be
What I have done is assuming the starting Node as parent Node I have collected all the child nodes plus the parentNode and using unwind looping each node collected and checking whether it has VALUE relationship and if so returning the values.
Hope this helps!
If not let me know what's the result you are expecting.
Thanks!

List of all Child B2BUnits

How to write a Flexible search Query to list all the Child B2BUnits of a Parent B2BUnit?
Ex: Parent B2BUnit: tc-0100
Child B2BUnit: tc-0101,tc-0102
If I search for Parent B2BUnit(tc-0100), I should get all the Child B2BUnits(tc-0101,tc-0102)
You can get all the children of the given b2bUnit(i.e tc-0100) with the following query:
select {pk} from {B2BUnit} where {pk} in ({{select {source} from {PrincipalGroupRelation} where {target}='$pkOfParentUnit$'}})
This flexible search query can be tried in hac after replacing $pkOfParentUnit$ with the actual PK of the given unit tc-0100 (the PK can be seen in the "Administration" tab in backoffice)
Explanation:
The inner query :
({{select {source} from {PrincipalGroupRelation} where {target}='$pkOfParentUnit$'}})
fetches all the members of a group(and in our case all the members of the given B2B unit) including B2BCustomers that might be assigned to it.
The beginning of the query makes sure that only the B2BUnits are present in the result and not B2BCustomers or other objects that might be also members.

Getting index of the resultset

Is there a way to get the index of the results within an aql query?
Something like
FOR user IN Users sort user.age DESC RETURN {id:user._id, order:{index?}}
If you want to enumerate the result set and store these numbers in an attribute order, then this is possible with the following AQL query:
LET sorted_ids = (
FOR user IN Users
SORT user.age DESC
RETURN user._key
)
FOR i IN 0..LENGTH(sorted_ids)-1
UPDATE sorted_ids[i] WITH { order: i+1 } IN Users
RETURN NEW
A subquery is used to sort users by age and return an array of document keys. Then a loop over a numeric range from the first to the last index of the that array is used to iterate over its elements, which gives you the desired order value (minus 1) as variable i. The current array element is a document key, which is used to update the user document with an order attribute.
Above query can be useful for a one-off computation of an order attribute. If your data changes a lot, then it will quickly become stale however, and you may want to move this to the client-side.
For a related discussion see AQL: Counter / enumerator
If I understand your question correctly - and feel free to correct me, this is what you're looking for:
FOR user IN Users
SORT user.age DESC
RETURN {
id: user._id,
order: user._key
}
The _key is the primary key in ArangoDB.
If however, you're looking for example data entered (in chronological order) then you will have to have to set the key on your inserts and/or create a date / time object and filter using that.
Edit:
Upon doing some research, I believe this link might be of use to you for AI the keys: https://www.arangodb.com/2013/03/auto-increment-values-in-arangodb/

loopback relational database hasManyThrough pivot table

I seem to be stuck on a classic ORM issue and don't know really how to handle it, so at this point any help is welcome.
Is there a way to get the pivot table on a hasManyThrough query? Better yet, apply some filter or sort to it. A typical example
Table products
id,title
Table categories
id,title
table products_categories
productsId, categoriesId, orderBy, main
So, in the above scenario, say you want to get all categories of product X that are (main = true) or you want to sort the the product categories by orderBy.
What happens now is a first SELECT on products to get the product data, a second SELECT on products_categories to get the categoriesId and a final SELECT on categories to get the actual categories. Ideally, filters and sort should be applied to the 2nd SELECT like
SELECT `id`,`productsId`,`categoriesId`,`orderBy`,`main` FROM `products_categories` WHERE `productsId` IN (180) WHERE main = 1 ORDER BY `orderBy` DESC
Another typical example would be wanting to order the product images based on the order the user wants them to
so you would have a products_images table
id,image,productsID,orderBy
and you would want to
SELECT from products_images WHERE productsId In (180) ORDER BY orderBy ASC
Is that even possible?
EDIT : Here is the relationship needed for an intermediate table to get what I need based on my schema.
Products.hasMany(Images,
{
as: "Images",
"foreignKey": "productsId",
"through": ProductsImagesItems,
scope: function (inst, filter) {
return {active: 1};
}
});
Thing is the scope function is giving me access to the final result and not to the intermediate table.
I am not sure to fully understand your problem(s), but for sure you need to move away from the table concept and express your problem in terms of Models and Relations.
The way I see it, you have two models Product(properties: title) and Category (properties: main).
Then, you can have relations between the two, potentially
Product belongsTo Category
Category hasMany Product
This means a product will belong to a single category, while a category may contain many products. There are other relations available
Then, using the generated REST API, you can filter GET requests to get items in function of their properties (like main in your case), or use custom GET requests (automatically generated when you add relations) to get for instance all products belonging to a specific category.
Does this helps ?
Based on what you have here I'd probably recommend using the scope option when defining the relationship. The LoopBack docs show a very similar example of the "product - category" scenario:
Product.hasMany(Category, {
as: 'categories',
scope: function(instance, filter) {
return { type: instance.type };
}
});
In the example above, instance is a category that is being matched, and each product would have a new categories property that would contain the matching Category entities for that Product. Note that this does not follow your exact data scheme, so you may need to play around with it. Also, I think your API query would have to specify that you want the categories related data loaded (those are not included by default):
/api/Products/13?filter{"include":["categories"]}
I suggest you define a custom / remote method in Product.js that does the work for you.
Product.getCategories(_productId){
// if you are taking product title as param instead of _productId,
// you will first need to find product ID
// then execute a find query on products_categories with
// 1. where filter to get only main categoris and productId = _productId
// 2. include filter to include product and category objects
// 3. orderBy filter to sort items based on orderBy column
// now you will get an array of products_categories.
// Each item / object in the array will have nested objects of Product and Category.
}

Sorting NSFetchedResultsController using a to-many relationship property

SCENARIO
I have two entities: Item and ListDetail (which contains prices for different lists for every item). This is absolutely needed and I can't provide a price attribute for the Item entity because every item can have more prices for different dynamic lists (retail, b2b ecc.).
The relationship is:
Item (lists) <------->> (item) ListDetail
The current active list in my app change dinamically, so let's say I have an integer variable with the current active list: _ACTIVE_LIST_CODE_. When I need a price for an item object I use an helper method on the Item class:
-(NSNumber*) getPrice {
NSSet *lists=[self.lists filteredSetUsingPredicate: [NSPredicate predicateWithFormat:#"listId == %d",_ACTIVE_LIST_CODE_]];
ListDetail *activeList=[[lists allObjects] objectAtIndex:0];
return activeList.price;
}
THE PROBLEM
I use a UITableView with NSFetchedResultController in order to select and show some items for different sections. Nothing special. I would like to order the fetchedObjects using the items price for the active list. If price was an attribute of Item I would added simply a sort descriptor to the fetch request like so:
[NSSortDescriptor sortDescriptorWithKey:#"price" ascending:YES];
But as said before this is not possible, price is a dynamic attribute.
If using transient properties was possible for sort descriptors, I would set a price transient properties calculated on fly using my helper method. Nothing to do.
Using a keypath in the descriptor like "lists.price" is not possible (or maybe I don't know how to do that), just because it's a to-many relationship and it's modeled with a NSSet.
I tried some workaround, without success:
1) observing _ACTIVE_LIST_CODE_ changes to set items price in a non-transient attribute.
2) after the fetch request, before presenting the table view, reorder a brand new array with fetched objects using the transient "price" property, iterate the orderdered array following an ascending integer index "i" and assigning this value to a non-transient property "order" for the Item entity. Using "order" for sort descriptor in the fetch request. (This approach is described here: Re-ordering NSFetchedResultsController)
Both of them works, but they slow down performance because I have thousands of items in the fetch results... Any idea?
How about fetching ListDetail instead? You could restrict and sort with the appropriate predicates and sort descriptors, exactly as you propose.
fetchRequest.predicate =
[NSPredicate predicateWithFormat:#"listID = %#", activeListCode];
fetchRequest.sortDescriptors =
#[[NSSortDescriptor sortDescriptorWithKey:#"price" ascending:YES]];
Now, to group by some attribute of item should be simple and efficient because it is a to-one relationship. Your fetched results controller's sectionNameKeyPath can be something like
#"item.category"

Resources