Arangodb Aql SORT not work for edge iteration - arangodb

I am try sort the result of edge iteration by 'beginAt' attribute but it don´t work for me
follows the aql code:
FOR f IN TRAVERSAL(client, careerEdges, "client/100", "outbound", {paths:true})
let sorted = (
FOR e IN f.path.edges
FILTER e.order <= 3
SORT e.beginAt DESC
RETURN e)
RETURN sorted
and the same to 'order' attribute. Always return the same sequence like this:
[
[],
[
{
"_id": "careerEdges/240469605275",
"_rev": "240469605275",
"_key": "240469605275",
"_from": "client/100",
"_to": "careers/iniAlt",
"order": 2,
"$label": "noLonger",
"beginAt": "2014-05-10 13:48:00",
"endAt": "2014-07-20 13:48:00"
}
],
[
{
"_id": "careerEdges/240470064027",
"_rev": "240470064027",
"_key": "240470064027",
"_from": "client/100",
"_to": "careers/lidGru",
"order": 3,
"$label": "noLonger",
"beginAt": "2014-07-20 13:48:00",
"endAt": "2014-08-20 13:48:00"
}
],
[
{
"_id": "careerEdges/240469867419",
"_rev": "240469867419",
"_key": "240469867419",
"_from": "client/100",
"_to": "careers/iniEst",
"endAt": null,
"order": 1,
"$label": "noLonger",
"beginAt": "2014-06-10 13:48:00"
}
]
]
My query is correctly?

Your query is producing a list of lists. The inner lists will be sorted by beginAt, but not the overall result.
If you want a flat list returned and sort it by some criterion, please try this instead:
FOR f IN TRAVERSAL(client, careerEdges, "client/100", "outbound", {paths:true})
FOR e IN f.path.edges
FILTER e.order <= 3
SORT e.beginAt DESC
RETURN e

Related

CosmosDb query to return arrays

I have the following data in my Collection
{
"id": "00000000-0000-0000-454c-4b74472b01d8",
"GroupId": 1,
"Location": "London",
"Status": "Ok"
},
{
"id": "d129adeb-d1bf-4a89-afe3-93e3f60589fb",
"GroupId": 1,
"Location": "Liverpool",
"Status": "Ok"
},
{
"id": "85ecf875-0e32-40b5-823a-a2545694f9b6",
"GroupId": 2,
"Location": "Manchester",
"Status": "Nok"
}
I need to build a query to get all possible value by Group for filtering.
Let's say for "GroupId": 1 I need result like
{
"Location": [
"London",
"Liverpool"
],
"Status": [
"Ok"
]
}
for "GroupId": 2 the response:
{
"Location": [
"Manchester",
],
"Status": [
"Nok"
]
}
Could you please help my to build such query? I don't know even if it possible with CosmosDb.
I have tried so far something like this but it doesn't work
select
(
select VALUE c.Location
FROM c
WHERE c.GroupId = 1
GROUP BY c.Location
) as Location,
(
select VALUE c.Status
FROM c
WHERE c.GroupId = 1
GROUP BY c.Status
) as Status
from c
WHERE c.GroupId = 1
and this
select
[
(SELECT VALUE [c.Location] from c)
] as Location,
[
(SELECT VALUE [c.Status] from c)
] as Status
from c
where c.GroupId = 1
Please help or suggest how to solve that. Thank you in advance.
It's not possible to do this with the way your data is modeled.
With the ARRAY expression you can do this in a subquery for arrays within your document. But not when the data spans documents as it is the case here.

How to merge all results of AQL into single document with custom properties

I have an AQL query traversing graph that always should return a fixed amount of documents from a unique set of collections.
So each collection will occur only once and with one document only.
I wish to merge them all into a single document under properties that reflects document’s collection name.
Query as simple as:
FOR v IN ANY "vertex/key" edge_collection RETURN v
Returns a sample result as:
[
{
"_key": "123",
"_id": "foo/123",
"_rev": "_WYhh0ji---",
"foo_attribute": "lorem impsum"
},
{
"_key": "456",
"_id": "bar/456",
"_rev": "_WYhh2ny---",
"bar_attribute": "dolor sit amet"
}
]
That I wish to get like this:
[
{
"foo": {
"_key": "123",
"_id": "foo/123",
"_rev": "_WYhh0ji---",
"foo_attribute": "lorem impsum"
},
"bar": {
"_key": "456",
"_id": "calendar/bar",
"_rev": "_WYhh2ny---",
"bar_attribute": "dolor sit amet"
}
}
]
In order to get collection name from document use PARSE_IDENTIFIER function that gives document’s collection name and key separately
Use square brackets comprehension to generate document property dynamically
Simply merge result of the query
Example:
RETURN MERGE(
FOR v IN ANY "vertex/key" edge_collection
RETURN {[PARSE_IDENTIFIER(v).collection]: v}
)

ArangoDB offset doesn't work in join

I got next tables: users_categories, users.
users_categories objects contains "users" fields which has keys only, so I make join:
FOR c IN users_categories
FILTER c._key == '75a65608-7e9b-4e74-be19-76882209e388'
FOR u IN c.users
FOR u2 IN users FILTER u == u2._key
LIMIT 0, 100
RETURN u2
Result:
[
{
"_key": "5b1b68db-9848-4a0a-81b3-775007f16845",
"_id": "users/5b1b68db-9848-4a0a-81b3-775007f16845",
"_rev": "_VXo9gaC---",
"activated": true,
"blocked": false,
"citizenship": "RU",
"city": "Kalinigrad",
"deleted": false,
"email": "trigger.trigg#yandex.ru",
"lastActivityTime": 1501539830209,
"login": "triggerJK",
"name": "Max",
"passportId": "8736e8e4-9390-44e7-9e21-b17e18b1ebd9",
"phone": "89092132022",
"profileName": "Default profile",
"sex": 1,
"surname": "Max"
},
{
"_key": "0965a0d9-fc91-449f-90f8-9086944b1a86",
"_id": "users/0965a0d9-fc91-449f-90f8-9086944b1a86",
"_rev": "_VWjRYHe---",
"activated": true,
"blocked": false,
"citizenship": "AF",
"deleted": false,
"email": "megamozg4#mail.ru",
"lastActivityTime": 1501247531,
"login": "Megamozg4",
"passportId": "20ab7aad-d356-4437-86b2-6dfa9c4467e0",
"phone": "12312334555",
"profileName": "Default profile",
"sex": 1
}
]
If I set LIMIT 1 or LIMIT 0, 1 it returns only first record, as I want to. However, if I set LIMIT 1, N (N can be any) it returns empty array, so offset doesn't work?
What am I doing wrong?
ArangoDB used: 3.1.10
UPD:
somehow, LIMIT 1, N skips not the only first record, but first 2.
If I have more than 2 records to show, offset works strange. I created issue on github
Two bugs were reported regarding offsets:
https://github.com/arangodb/arangodb/issues/2928
https://github.com/arangodb/arangodb/issues/2879
And the fixes for LIMIT are included in the versions v3.1.27 and v3.2.1, so please update and test again.

Return distinct and sorted query in AQL

So I have two collections, one with cities with an array of postal codes as a property and one with postal codes and their latitude & longitude.
I want to return the cities closest to a coordinate. This is easy enough with a geo index but the issue I'm having is the same city being returned multiple times and some times it can be the 1st and 3rd closest because the postal code that I'm searching in bordering another city.
cities example data:
[
{
"_key": "30936019",
"_id": "cities/30936019",
"_rev": "30936019",
"countryCode": "US",
"label": "Colorado Springs, CO",
"name": "Colorado Springs",
"postalCodes": [
"80904",
"80927"
],
"region": "CO"
},
{
"_key": "30983621",
"_id": "cities/30983621",
"_rev": "30983621",
"countryCode": "US",
"label": "Manitou Springs, CO",
"name": "Manitou Springs",
"postalCodes": [
"80829"
],
"region": "CO"
}
]
postalCodes example data:
[
{
"_key": "32132856",
"_id": "postalCodes/32132856",
"_rev": "32132856",
"countryCode": "US",
"location": [
38.9286,
-104.6583
],
"postalCode": "80927"
},
{
"_key": "32147422",
"_id": "postalCodes/32147422",
"_rev": "32147422",
"countryCode": "US",
"location": [
38.8533,
-104.8595
],
"postalCode": "80904"
},
{
"_key": "32172144",
"_id": "postalCodes/32172144",
"_rev": "32172144",
"countryCode": "US",
"location": [
38.855,
-104.9058
],
"postalCode": "80829"
}
]
The following query works but as an ArangoDB newbie I'm wondering if there's a more efficient way to do this:
FOR p IN WITHIN(postalCodes, 38.8609, -104.8734, 30000, 'distance')
FOR c IN cities
FILTER p.postalCode IN c.postalCodes AND c.countryCode == p.countryCode
COLLECT close = c._id AGGREGATE distance = MIN(p.distance)
FOR c2 IN cities
FILTER c2._id == close
SORT distance
RETURN c2
The first FOR in the query will use the geo index and probably return few documents (just the postal codes around the specified location).
The second FOR will look up the city for each found postal code. This may be an issue, depending on whether there is an index present on cities.postalCodes and cities.countryCode. If not, then the second FOR has to do a full scan of the cities collection each time it is involved. This will be inefficient. It may therefore be create an index on the two attributes like this:
db.cities.ensureIndex({ type: "hash", fields: ["countryCode", "postalCodes[*]"] });
The third FOR can be removed entirely when not COLLECTing by c._id but by c:
FOR p IN WITHIN(postalCodes, 38.8609, -104.8734, 30000, 'distance')
FOR c IN cities
FILTER p.postalCode IN c.postalCodes AND c.countryCode == p.countryCode
COLLECT city = c AGGREGATE distance = MIN(p.distance)
SORT distance
RETURN city
This will shorten the query string, but it may not help efficiency much I think, as the third FOR will use the primary index to look up the city documents, which is O(1).
In general, when in doubt about a query using indexes, you can use db._explain(queryString) to show which indexes will be used by a query.

Using ArangoDB EDGES function, can't get the right vertex with includeVertices options

Using ArangoDB to describe a friend relationship, I want to know the friends of a specific user A. Because it's a test sample, I know that A is friend with B.
I have users in a document collection and an edge collection containing the information from "_from" being friend to "_to". If A is friend to B, B must be friend to A. i.e.: if there's an edge _from A _to B, an other edge _from B _to A does exist.
I use the function EDGES on my friend collection, to know which is friend to the user "u4", which _id is 2465087832. He must be friend with "u1", which _id is 2462335320.
Because I want to have more than just the document ID, I set the option "includeVertices" to true.
Here are my request.
LET out = EDGES(friends, "db/2465087832", "outbound", null, {includeVertices: true})
And the answer:
[
{
"edge": {
"_id": "db/2468102488",
"_from": "db/2465087832",
"_to": "db/2462335320",
"_rev": "2468102488",
"_key": "2468102488"
},
"vertex": {
"_id": "db/2465087832",
"_key": "2465087832",
"_rev": "3962323288",
"id": "u4"
}
}
]
As a result, I have the good edge (u4 is friend to u1), but the vertex included is the one from the requested user (id: u4).
I tried using "inbound" as a direction, instead of "outbound".
LET out = EDGES(friends, "db/2465087832", "inbound", null, {includeVertices: true})
And the result is:
[
{
"edge": {
"_id": "db/2468364632",
"_from": "db/2462335320",
"_to": "db/2465087832",
"_rev": "2468364632",
"_key": "2468364632"
},
"vertex": {
"_id": "db/2465087832",
"_key": "2465087832",
"_rev": "3962323288",
"id": "u4"
}
}
]
As you can see, still "u4" as vertex, even is the edge is the good one (u1 is friend to u4).
At last, I tried to use "any" as a direction.
LET any = EDGES(friends, "db/2465087832", "any", null, {includeVertices: true})
And the surprising answer:
[
{
"edge": {
"_id": "friends/2468364632",
"_from": "user/2462335320",
"_to": "user/2465087832",
"_rev": "2468364632",
"_key": "2468364632"
},
"vertex": {
"_id": "user/2462335320",
"_rev": "3956687192",
"_key": "2462335320",
"id": "u1"
}
},
{
"edge": {
"_id": "friends/2468102488",
"_from": "user/2465087832",
"_to": "user/2462335320",
"_rev": "2468102488",
"_key": "2468102488"
},
"vertex": {
"_id": "user/2462335320",
"_rev": "3956687192",
"_key": "2462335320",
"id": "u1"
}
}
]
Here the answer contains both edge (A to B and B to A) which is correct, but for both the vertex is the one from u1. This three results seem to be inconsistent: for "inbound"/"outbound" : the vertex was u4, and for "any" the vertex is "u1".
Is there a bug in my code? An option that I should use?
Thanks,
BobCitron
thank you very much for spotting this, it is actually a bug in our core not in your code
I did just fix it and it will be included in the next 2.6. bugfix release and in 2.7(devel).
The expected behaviour is as you describe.
Do you actually need the information stored in the Edges?
If not you could consider using the NEIGHBORS function in this case, which is more performant.

Resources