I have the following OData V4 query:
.../odata/Locations/?$select=Id&$filter=(Id eq 9bb29421-5160-4546-b87f-a78c0074f5c5 or Id eq 8b2a9727-a642-446e-b992-76c6d1584989)&$expand=Assets($select=Id;$filter=ParentAssetId eq null;$expand=Jobs($select=Id;$count=true;$top=0))
with the following, as expected, result:
{
"#odata.context": ".../odata/$metadata#Locations(Id,Assets(Id,Jobs(Id)))",
"value": [
{
"Id": "8b2a9727-a642-446e-b992-76c6d1584989",
"Assets": [
{
"Id": "540d0855-aa1c-4e94-9d0b-332c99ec00b6",
"Jobs#odata.count": 2,
"Jobs": []
},
{
"Id": "6dcaa0e8-fc31-4d86-9f1a-a64300f8815c",
"Jobs#odata.count": 1,
"Jobs": []
},
{
"Id": "db4cf86b-9f42-4a99-b7b4-a64300f8c740",
"Jobs#odata.count": 1,
"Jobs": []
}
]
},
{
"Id": "9bb29421-5160-4546-b87f-a78c0074f5c5",
"Assets": [
{
"Id": "08a2a046-86c1-41a9-b2b1-a7ac007bed64",
"Jobs#odata.count": 1,
"Jobs": []
},
{
"Id": "2b76dad1-4058-4261-8a40-a7af00cb8bd5",
"Jobs#odata.count": 1,
"Jobs": []
},
{
"Id": "3a5472a1-68c4-4dc4-b2cd-a797007b0068",
"Jobs#odata.count": 2,
"Jobs": []
}
]
}
]
}
How can I sum the Jobs#odata.count values and return a single value: 8?
I have tried some &$apply=aggregate(Assets/Jobs#odata.count with sum as Total) but it is an incorrect syntax :(
I fixed this by changing the query perspective and count the Jobs from the beginning:
.../odata/Jobs/$count/?$expand=Asset($select=LocationId)&$filter=Asset/LocationId in (9bb29421-5160-4546-b87f-a78c0074f5c5, 8b2a9727-a642-446e-b992-76c6d1584989)
Related
I have this grammar:
let lexer = moo.compile({
comment: { match: /[\/\/.*?$|][^\n]+/, value: (s:string) => s.slice(1).trim() },
newline: { match: /[\n]+/, lineBreaks: true }
});
%}
#lexer lexer
main ->
element
| main %newline element
element -> comment
comment -> %comment
Now when I feed nearley the following input: //\n//\n//\n//\n// I get this result:
[
[
[
[
[
[
[
[
{
"type": "comment",
"value": "/",
"text": "//",
"offset": 0,
"lineBreaks": 0,
"line": 1,
"col": 1
}
]
]
],
{
"type": "newline",
"value": "\n",
"text": "\n",
"offset": 2,
"lineBreaks": 1,
"line": 1,
"col": 3
},
[
[
{
"type": "comment",
"value": "/",
"text": "//",
"offset": 3,
"lineBreaks": 0,
"line": 2,
"col": 1
}
]
]
],
{
"type": "newline",
"value": "\n",
"text": "\n",
"offset": 5,
"lineBreaks": 1,
"line": 2,
"col": 3
},
[
[
{
"type": "comment",
"value": "/",
"text": "//",
"offset": 6,
"lineBreaks": 0,
"line": 3,
"col": 1
}
]
]
],
{
"type": "newline",
"value": "\n",
"text": "\n",
"offset": 8,
"lineBreaks": 1,
"line": 3,
"col": 3
},
[
[
{
"type": "comment",
"value": "/",
"text": "//",
"offset": 9,
"lineBreaks": 0,
"line": 4,
"col": 1
}
]
]
],
{
"type": "newline",
"value": "\n",
"text": "\n",
"offset": 11,
"lineBreaks": 1,
"line": 4,
"col": 3
},
[
[
{
"type": "comment",
"value": "/",
"text": "//",
"offset": 12,
"lineBreaks": 0,
"line": 5,
"col": 1
}
]
]
]
]
I dont quite understand why the resulting array is so deeply nested and if theres a way to just have it flat for each elements. Like comments on the same semantic level should be part of one array and not nested.
Okay, so it turns out you have to pass a post-processor to each rule if you don't want them nested in arrays.
For instance like this:
main ->
element {% d => ({ type: "main_element", data: d[0]}) %}
| main %newline element {% d => ({ type: "main_element", data: d[2], main_data: d[0]}) %}
element -> %comment
{% d => ({ type: "element", data: d[0]}) %}
This will result in a flat structure as expected:
[
{
"type": "main_element",
"data": {
"type": "element",
"data": {
"type": "comment",
"value": "/",
"text": "//",
"offset": 12,
"lineBreaks": 0,
"line": 5,
"col": 1
}
},
"main_data": {
"type": "main_element",
"data": {
"type": "element",
"data": {
"type": "comment",
"value": "/",
"text": "//",
"offset": 9,
"lineBreaks": 0,
"line": 4,
"col": 1
}
},
"main_data": {
"type": "main_element",
"data": {
"type": "element",
"data": {
"type": "comment",
"value": "/",
"text": "//",
"offset": 6,
"lineBreaks": 0,
"line": 3,
"col": 1
}
},
"main_data": {
"type": "main_element",
"data": {
"type": "element",
"data": {
"type": "comment",
"value": "/",
"text": "//",
"offset": 3,
"lineBreaks": 0,
"line": 2,
"col": 1
}
},
"main_data": {
"type": "main_element",
"data": {
"type": "element",
"data": {
"type": "comment",
"value": "/",
"text": "//",
"offset": 0,
"lineBreaks": 0,
"line": 1,
"col": 1
}
}
}
}
}
}
}
]
I run
Post.search("daniel")
I get 60+ results
Post.where(archive: true)
I get 60+ results
Post.search("daniel", where: { archive: true }
Here is the full searchkick query.
I get 0 results
{
"query": {
"bool": {
"must": {
"bool": {
"should": [
{
"dis_max": {
"queries": [
{
"multi_match": {
"query": "daniel",
"boost": 10,
"operator": "and",
"analyzer": "searchkick_search",
"fields": [
"*.analyzed"
],
"type": "best_fields"
}
},
{
"multi_match": {
"query": "daniel",
"boost": 10,
"operator": "and",
"analyzer": "searchkick_search2",
"fields": [
"*.analyzed"
],
"type": "best_fields"
}
},
{
"multi_match": {
"query": "daniel",
"boost": 1,
"operator": "and",
"analyzer": "searchkick_search",
"fuzziness": 1,
"prefix_length": 0,
"max_expansions": 3,
"fuzzy_transpositions": true,
"fields": [
"*.analyzed"
],
"type": "best_fields"
}
},
{
"multi_match": {
"query": "daniel",
"boost": 1,
"operator": "and",
"analyzer": "searchkick_search2",
"fuzziness": 1,
"prefix_length": 0,
"max_expansions": 3,
"fuzzy_transpositions": true,
"fields": [
"*.analyzed"
],
"type": "best_fields"
}
}
]
}
}
]
}
},
"filter": [
{
"term": {
"archive": {
"value": true
}
...
I looked at the searchkick gem doc and I am following exactly what they have listed to do. The normal search works fine and it only returns 0 posts when I add the where clause.
Without the where clause it shows all the posts which have "daniel" in the and it breaks when the where clause is added.
What am I doing wrong here? Is more information needed?
require 'elasticsearch/model'
class Post < ApplicationRecord
searchkick text_start: [:title]
I have nodes with these properties:
MATCH (n:A) RETURN n
[
{
"name": "114s09A.1",
"_id": "114s09A.1",
"id": "114s09A.1",
"created_n4j": "2020-12-21T09:56:11.256000000Z",
"type": "A",
"updated_n4j": "2020-12-21T09:56:11.256000000Z"
},
{
"name": "114s09A.2",
"_id": "114s09A.2",
"id": "114s09A.2",
"created_n4j": "2020-12-21T09:56:11.257000000Z",
"type": "A",
"updated_n4j": "2020-12-21T09:56:11.257000000Z"
}
]
Is there a way to build the cypher query so that the result would be shaped as a dictionary where id would be the key ?
[
{
"114s09A.1": {
"name": "114s09A.1",
"id": "114s09A.1",
"created_n4j": "2020-12-21T09:56:11.256000000Z",
"type": "A",
"updated_n4j": "2020-12-21T09:56:11.256000000Z"
}
},
{
"114s09A.2": {
"name": "114s09A.2",
"id": "114s09A.2",
"created_n4j": "2020-12-21T09:56:11.257000000Z",
"type": "A",
"updated_n4j": "2020-12-21T09:56:11.257000000Z"
}
}
]
The closest I came up to so far is :
MATCH (n:A) RETURN n._id AS _id, properties(n) AS properties
[
{
"_id":"114s09A.1",
"properties":{
"name": "114s09A.1",
"id": "114s09A.1",
"created_n4j": "2020-12-21T09:56:11.256000000Z",
"type": "A",
"updated_n4j": "2020-12-21T09:56:11.256000000Z"
}
},
{
"_id":"114s09A.2",
"properties":{
"name": "114s09A.2",
"id": "114s09A.2",
"created_n4j": "2020-12-21T09:56:11.257000000Z",
"type": "A",
"updated_n4j": "2020-12-21T09:56:11.257000000Z"
}
}
]
It's not possible with the default Cypher syntax, however if you have the apoc library installed, you can do this :
MATCH (n:A)
RETURN apoc.map.setKey({}, n.id, n{.*})
What's the best way to sum all the "amounts" of all "expenses", for each user?
I've tried a few different things but I can't quite get it right. It should return 2 values: 20.0 and 24.90
[
{
"id": 3,
"company": {
"id": 2
},
"user": {
"id": 3,
"first_name": "Fred",
"last_name": "Smith",
"email": "asdfasf",
"is_suspended": false,
"vendor_id": "FS-100",
"username": "etytyurtyu",
"expense": [
{
"id": 7,
"date": "2019-12-14T00:00:00.000Z",
"amount": 20.0,
"payment_type": "companyAccount",
"last_modified": "2019-12-16T23:50:00.459064Z",
"receipt_uri": [
"URL8",
"URL9"
],
"user": {
"id": 3
},
"expense_type": {
"id": 4
},
"booking": {
"id": "HI-3565346"
}
}
]
}
},
{
"id": 2,
"company": {
"id": 2
},
"user": {
"id": 2,
"first_name": "Pierre",
"last_name": "XXXMar",
"email": "asdfasdfads",
"is_suspended": false,
"vendor_id": "PM-100",
"username": "asdfas",
"expense": [
{
"id": 2,
"date": "2019-12-16T00:00:00.000Z",
"amount": 12.45,
"payment_type": "provided",
"last_modified": "2019-12-16T19:01:37.092932Z",
"receipt_uri": [
"URL1"
],
"user": {
"id": 2
},
"expense_type": {
"id": 6
},
"booking": {
"id": "MU-123414"
}
},
{
"id": 5,
"date": "2019-12-08T00:00:00.000Z",
"amount": 12.45,
"payment_type": "provided",
"last_modified": "2019-12-16T23:50:00.459064Z",
"receipt_uri": [
"URL1"
],
"user": {
"id": 2
},
"expense_type": {
"id": 6
},
"booking": {
"id": "MU-123414"
}
},
{
"id": 3,
"date": "2019-12-17T00:00:00.000Z",
"amount": 20.0,
"payment_type": "companyCard",
"last_modified": "2019-12-16T19:01:37.092932Z",
"receipt_uri": [
"URL5",
"URL6"
],
"user": {
"id": 2
},
"expense_type": {
"id": 12
},
"booking": {
"id": "HI-3565346"
}
}
]
}
}
]
Thanks
You would first map the expenses amounts, then fold it into a single value, like this :
double sum = expenses.map((expense) => expense.amount).fold(0, (prev, amount) => prev + amount);
List item
For the sake of completeness: In 2021 you can replace the .fold(0, (prev, amount) => prev + amount) part by just calling .sum on the list. Just import import 'package:collection/collection.dart'; first –
tmaihoff
Given the following result in my cypher query, where people are a collection:
[
{
"people": [
{
"id": 24749,
"matches": 1
},
{
"id": 26026,
"matches": 1
},
{
"id": 26223,
"matches": 1
},
{
"id": 25121,
"matches": 1
},
{
"id": 24632,
"matches": 1
},
{
"id": 25708,
"matches": 1
},
{
"id": 25182,
"matches": 1
},
{
"id": 24826,
"matches": 1
},
{
"id": 26186,
"matches": 1
},
{
"id": 27001,
"matches": 1
},
{
"id": 24243,
"matches": 1
},
{
"id": 27255,
"matches": 1
},
{
"id": 27145,
"matches": 1
},
{
"id": 24126,
"matches": 1
},
{
"id": 27463,
"matches": 1
},
{
"id": 24069,
"matches": 1
},
{
"id": 25210,
"matches": 1
},
{
"id": 24994,
"matches": 1
},
{
"id": 27331,
"matches": 1
},
{
"id": 25793,
"matches": 1
},
{
"id": 27312,
"matches": 1
},
{
"id": 26206,
"matches": 1
},
{
"id": 24252,
"matches": 1
},
{
"id": 24714,
"matches": 2
},
{
"id": 24612,
"matches": 1
},
{
"id": 26964,
"matches": 1
},
{
"id": 27101,
"matches": 1
},
{
"id": 26730,
"matches": 1
},
{
"id": 27211,
"matches": 1
},
{
"id": 24783,
"matches": 2
},
{
"id": 25336,
"matches": 1
},
{
"id": 24128,
"matches": 1
},
{
"id": 26186,
"matches": 1
},
{
"id": 25125,
"matches": 2
},
{
"id": 24069,
"matches": 3
},
{
"id": 24607,
"matches": 1
},
{
"id": 27055,
"matches": 1
},
{
"id": 25336,
"matches": 3
},
{
"id": 24128,
"matches": 2
},
{
"id": 26716,
"matches": 1
},
{
"id": 27331,
"matches": 1
},
{
"id": 24069,
"matches": 1
}
]
}
]
How can I (with cypher) iterate the people collection and find the ones with the same "id", sum the "matches" items together and then add a new item called "duplicates" or similar.
Example result I'm trying to get:
[
{
"people": [
{
"id": 24069,
"matches": 5, // all the "matches" of the duplicate 24069's added together
"duplicates": 3 // how may times the id 24069 was found in the collection called people
},
// etc...
]
}
]
The query:
match (p:people) return distinct(p.id),sum(p.matches)
should probably give you what you need
This is kinda complicated, as the simplest way is to tear your collection apart and reassemble it. It's a lot of steps, but here is the Cypher to do that as well as comments on what each step is doing.
// initial matching (whatever you match on to get your collection)
MATCH (n:People) WITH collect(n) as people
// Tear people collection apart for possessing
UNWIND people as p
// Reduce on id
WITH COLLECT(DISTINCT p.id) as id, p.matches as m
// For each id, sum and count the matches
WITH {id:id, matches:SUM(m), duplicates:COUNT(m)} as people
// Recollect rows into collection
RETURN COLLECT(people) as people