Merge an Array of Documents in RethinkDB - join

Let's say I have a table called bookshelf. I create a bookshelf document that has an array of IDs that references books in another table called books. I am trying to use getAll and merge to combine the documents in a query but I cannot seem to be able to pass all the elements into getAll. I believe getAll is interpreting the array of IDs as a single literal "object".
A bookshelf document:
{
id: 'MyShelf'
books: [ 1, 2, 6, 9 ]
}
A book document:
{
id: 1
name: 'Merging in RethinkDB for Dummies'
}
My query:
r.db('test').table('bookshelf').merge(function(bookshelf) {
return {
booksOnShelf: r.table('books').getAll(bookshelf('books')).coerceTo('array')
}
})
Expected result:
{
id: 'MyShelf'
books: [ 1, 2, 6, 9 ],
booksOnShelf: [
{ id: 1, name: 'Merging in RethinkDB for Dummies' },
{ id: 2, name: 'Cool Title!' },
...
]
}
Actual result:
{
id: 'MyShelf'
books: [ 1, 2, 6, 9 ],
booksOnShelf: [ ]
}

It turns out that I needed to use r.args to turn the array into actual arguments for use with the getAll function.
Here is the correct query:
r.db('test').table('bookshelf').merge(function(bookshelf) {
return {
booksOnShelf: r.table('books').getAll(r.args(bookshelf('books'))).coerceTo('array')
}
})
And the result:
{
"books": [ 1, 2 ],
"booksOnShelf": [{
"id": 1,
"title": "RethinkDB for Dummies"
}, {
"id": 2,
"title": "Awesome Title!"
}],
"id": "MyShelf"
}

Related

How to use ORDER BY and LIMIT on node children but not their parents? Cypher

I have a set of Author nodes. An Author node is the single parent of multiple Book nodes.
My goal: To print all Author nodes with no order and no limit, with each authors' first three books in alphabetical order.
Desired output: (let's pretend book names are a single letter)
[
{
"name" : "Leo Tolstoy",
"books": [
{ "name": "A" },
{ "name": "B" },
{ "name": "D" }
]
},
{
"name": "Charles Dickens",
"books": [
{ "name": "C" },
{ "name": "E" },
{ "name": "F" }
]
},
{
"name": "Oscar Wilde
...
]
My Problem:
I tried this:
MATCH(author:Author)
WITH author
OPTIONAL MATCH(author)-[:WROTE]->(book:Book)
WITH author, book
ORDER BY book.name
LIMIT 3
WITH author, collect(book) AS books
RETURN collect (
{
name: author.name,
books: books
}
);
But this gives:
[
{
"name" : "Leo Tolstoy",
"books": [
{ "name": "A" },
{ "name": "B" },
]
},
{
"name": "Charles Dickens",
"books": [
{ "name": "C" }
]
}
]
How could I achieve my desired output in Neo4j v3.5?
[EDITED]
This should work:
MATCH(author:Author)
OPTIONAL MATCH(author)-[:WROTE]->(book:Book)
WITH author, book.name AS bookName
ORDER BY bookName
WITH author, COLLECT({name: bookName})[..3] AS bookNames
RETURN COLLECT({name: author.name, books: bookNames}) AS result

How to normalize this recursive nested JSON

Having a bit of an issue trying to normalise the my payload that contains a nested schema of the same type as the parent using Normalizr
For example
{
id: 123,
sections:{
section: [{
id: 1,
name: "test",
sections: {
section: {
id: 125,
name: "test125"
}
}
}, {
id: 2,
name: "test2"
sections: {
section: [
{
id: 124,
name: "test124"
}
]
}
}, {
id: 3,
name: "test3"
}]
}
}
In the above json structure, nested section may be an object or an array.
I had a similar issue with nested comments. Here's how I solved it:
export const comment = new schema.Entity("comment", {}, {
idAttribute: "key"
})
comment.define({
user: user,
reactions: {
data: [reaction]
},
children: [comment]
})
export const post = new schema.Entity("post", {
user: user,
files: [image],
comments: {
data: [comment]
},
reactions: {
data: [reaction]
}
}, {
idAttribute: "key"
})
Basically, I define comment as a new entity before I use it in its own entity definition. The other schemas I define as usual, in the constructor (see the post schema for an example). Hope this helps.
Here is a jq filter which will normalize the data:
def enumerate:
if type=="array" then .[] else . end ;
def sectionids:
[ .sections.section | enumerate | .id // empty | tostring ]
| if .==[] then {} else {sections:.} end ;
def sections:
{sections:{section:[.]}}
| .. | .section? | enumerate | objects | del(.sections) + sectionids ;
{
"result": .id,
"entities": {
"sections": (reduce sections as $s ({};.["\($s.id)"]=$s))
}
}
Sample Run (assumes proper json data in data.json and the above filter in filter.jq)
$ jq -M -f filter.jq data.json
{
"result": 123,
"entities": {
"sections": {
"123": {
"id": 123,
"sections": [
"1",
"2",
"3"
]
},
"1": {
"id": 1,
"name": "test",
"sections": [
"125"
]
},
"2": {
"id": 2,
"name": "test2",
"sections": [
"124"
]
},
"3": {
"id": 3,
"name": "test3"
},
"125": {
"id": 125,
"name": "test125"
},
"124": {
"id": 124,
"name": "test124"
}
}
}
}
Try it online!

Relationship not being created, match by Id not returning results

I'm just getting started with Neo4j.
I'm trying to do a complex LOAD FROM CSV but I don't seem to be getting the relations part right.
LOAD CSV WITH HEADERS FROM "file:/Users/brestrepo/Krossover/neo4j/access_control_games.csv" AS csvLine
MERGE (game:Game
{
id: toInt(csvLine.id),
datePlayed: csvLine.date_played,
type: csvLine.type,
createdAt: csvLine.created_at,
updatedAt: csvLine.updated_at
}
)
FOREACH(ignoreMe IN CASE WHEN trim(csvLine.deleted_at) <> "" THEN [1] ELSE [] END | SET game.deletedAt = csvLine.deleted_at)
WITH csvLine, game
MATCH (team:TEAM { id: toInt(csvLine.created_by_team_id)}),(game:Game { id: toInt(csvLine.id)})
CREATE (team)-[:OWNER_TEAM { }]->(game)
WITH csvLine, game
MATCH (user:User { id: toInt(csvLine.created_by_user_id)}),(game:Game { id: toInt(csvLine.id)})
CREATE (user)-[:OWNER_USER { }]->(game)
WITH csvLine, game
MATCH (team_away:TEAM { id: toInt(csvLine.team_away_id)}),(game:Game { id: toInt(csvLine.id)})
CREATE (team_away)-[:AWAY_TEAM { }]->(game)
WITH csvLine, game
MATCH (team_home:TEAM { id: toInt(csvLine.team_home_id)}),(game:Game { id: toInt(csvLine.id)})
CREATE (team_home)-[:HOME_TEAM { }]->(game)
RETURN game
I think that the MATCH is that's causing this problem. The Match is unable to find a game.
I do get games when I do:
MATCH (game:Game) return game LIMIT 1
{
"records": [
{
"keys": [
"game"
],
"length": 1,
"_fields": [
{
"identity": {
"low": 31891,
"high": 0
},
"labels": [
"Game"
],
"properties": {
"createdAt": "2014-07-18 19:38:32",
"deletedAt": "NULL",
"id": {
"low": 285,
"high": 0
},
"type": "2",
"datePlayed": "2013-10-12 04:00:00",
"updatedAt": "2016-03-25 15:28:41"
},
"id": "31891"
}
],
"_fieldLookup": {
"game": 0
}
}
],
}
But then, when I do
MATCH (game:Game {id: 31891}) return game;
(no changes, no records)
Can anyone point me in the right direction?

Get specific json data rails

I have this json data (actual data is a lot longer, that's why I need only 2)
[
{
"id": 1,
"user_id": 1,
"event_id": 1,
"creator_id": 1,
"event_name": "Poker",
"cruise_ship_name": "Royal Cruise",
},
{
"id": 2,
"user_id": 1,
"event_id": 2,
"creator_id": 1,
"event_name": "Ballroom",
"cruise_ship_name": "Celebrity Infinity",
},
{
"id": 3,
"user_id": 1,
"event_id": 3,
"creator_id": 1,
"event_name": "Tennis",
"cruise_ship_name": "Mediterranean",
}
]
I want to combine all data and get only specific fields (event_name and cruise_ship_name)
So in my final json format
it will be:
[
{
"event_name": "Mexican Fiesta",
"cruise_ship_name": "Celebrity Infinity",
}
]
I have been looking at this example:
#object.to_json {:include => [ :assocation_a, :assocation_b ]}
but not sure what :association_a and :association_b are.
Suppose you have an array of hashes:
events = [
{
"id": 1,
"user_id": 1,
"event_id": 1,
"creator_id": 1,
"event_name": "Poker",
"cruise_ship_name": "Royal Cruise",
},
...
]
You can iterate through each value in your hash, only keeping values of interest:
events.each do |event_hash|
event_hash.keep_if { |key, _| [:event_name, :cruise_ship_name].include?(key) }
end
puts events
The to_json method accept parameters which allow you include specific attributes:
#object.to_json(only: [:event_name, :cruise_ship_name])
The include: :assocation_a option to object, allowing the object association in the assocation_a model to be converted to JSON as well.

How to return relationship type with Neo4J's Cypher queries?

I am trying to get the relationship type of a very simple Cypher query, like the following
MATCH (n)-[r]-(m) RETURN n, r, m;
Unfortunately this return an empty object for r. This is troublesome since I can't distinguish between the different types of relationships. I can monkey patch this by adding a property like [r:KNOWS {type:'KNOWS'}] but I am wondering if there isn't a direct way to get the relationship type.
I even followed the official Neo4J tutorial (as described below), demonstrating the problem.
Graph Setup:
create (_0 {`age`:55, `happy`:"Yes!", `name`:"A"})
create (_1 {`name`:"B"})
create _0-[:`KNOWS`]->_1
create _0-[:`BLOCKS`]->_1
Query:
MATCH p=(a { name: "A" })-[r]->(b)
RETURN *
JSON RESPONSE BODY:
{
"results": [
{
"columns": [
"a",
"b",
"p",
"r"
],
"data": [
{
"row": [
{
"name": "A",
"age": 55,
"happy": "Yes!"
},
{
"name": "B"
},
[
{
"name": "A",
"age": 55,
"happy": "Yes!"
},
{},
{
"name": "B"
}
],
{}
]
},
{
"row": [
{
"name": "A",
"age": 55,
"happy": "Yes!"
},
{
"name": "B"
},
[
{
"name": "A",
"age": 55,
"happy": "Yes!"
},
{},
{
"name": "B"
}
],
{}
]
}
]
}
],
"errors": []
}
As you can see, I get an empty object for r, which makes it impossible to distinguish between the relationships.
NOTE: I am running Neo4J v.2.2.2
Use the type() function.
MATCH (n)-[r]-(m) RETURN type(r);
Added distinct.
MATCH (n)-[r]-(m) RETURN distinct type(r);

Resources