neo4j cypher nested collect - neo4j

Imagine a photo album schema w/ Users, Albums, and Photos:
User -[owns]-> Album -[contains]-> Photo
Can I do a nested collect to get Photos nested in Albums, and Albums nested in User? I'd like results similar to:
{ "users": [
{ "name": "roger dodger",
"albums": [
{ "album": "album1",
"photos": [
{"url": "photo1.jpg"},
{"url": "photo2.jpg"}
]
}
]
}
]
}
This seems close but I could not modify it to suit my needs: Nested has_many relationships in cypher
(Could the problem be that neo4j 2.0 web console doesn't support the json syntax in that example?)

Try this query:
MATCH (a:USER)-[:owns]->(b:ALBUM)-[:CONTAINS]->(c:PHOTO)
WITH a,b,{url: c.name} as c_photos
WITH a,{album: b.name , photos: collect(c_photos)} as b_albums
WITH {name: a.name, albums: collect(b_albums)} as a_users
RETURN {users: collect(a_users)}
Edit
To get all properties of a node you can use string representation of the node and then parse it separately using java etc
MATCH (a:User)
WITH {user: str(a)} as users
RETURN {users: collect(users)}

Related

Elasticsearch match field=value (not contains)

I have problem while searching through elasticsearch.
I have index product with fields title and gender
When I make query with default_field: title I need to get results only with gender=male (not female or others)
query: dress AND gender:male
Results contain both genders: male and female and male,female
It seems to me that gender:* search all which contains male, but not full match of value. How to do the query right?
I use it through Ruby on Rails
Product.search({
query: {
query_string: {
query: query,
default_field: "title"
}
},
size: per_page,
sort: [ _score: { order: relevance } ]
})
Is gender a keyword data type? I suspect that you left/set the default mapping to the gender field (i.e., text + keyword subfield). In this case, try the following query: dress AND gender.keyword:male
According with this I just need to put value in double quotes..
query = '(dress) AND (gender:"male")'
do not forget to escape them if needed "gender:\"male\""

Multiple Search terms using Ruby Searchkick

I have set everything up using ElasticSearch and SearchKick, however, I cannot get it to work quite like I want to. I need to have multiple searches.
My model, Car, has two attributes such as "Make" and "Year". I can do this:
Car.search( query: { match: {make: { query: "toyota" } }} )
How do I also find matches that belong to Toyoto but also belonging to a specific year, say 2012.
Thank you
Assuming that year is either an attribute of your Car model or defined explicitly in your search_data config this should work:
Car.search "toyota", where: { year: 2012 }
This will returns cars in which make is "toyota" AND year is 2012
Car.search "*", where: { make: 'toyota', year: 2012 }
For make is "toyota" OR year is 2012
Car.search "*", where: { or: [[{make: 'toyota'},{year: 2012}]] }

Is it possible to upsert documents in mondodb by an array of ids, so that each new created document's _id is the one from the array?

In my Rails project with mongodb, I retrieve user ids from twitter which I want to store in my User model. The plan is to upsert the collection of Users with the retrieved user ids I have in an array, and set every new created document _id to the corresponding user id from the array.
So when I do something like this:
Tweep.collection.find( _id: 1234567 ).modify( { "$set" => {a: true}, "$unset" => {c: ""} }, {upsert: true})enter code here
The result is like expected: <Tweep _id: 1234567, a(active): true, c(candidate_value): nil>
Now I want to do the same, but only passing an array of ids to upsert my collection on Users:
Tweep.collection.find(_id: {"$in" =>[123124,223553,6343643,23423]}, c: { "$exists" => true }).modify( { "$set" => {p: true}, "$inc" => {c: 1} }, {upsert: true})
The result is some newly created documents, but without the desired values as _id e.g. _id: 123124:
<Tweep _id: 5244501325fed0cfd2c1a615, a(active): nil, c(candidate_value): 1>
instead of:
<Tweep _id: 123124, a(active): nil, c(candidate_value): 1>
How can I make mongodb use the user id in my array to be the id for the field _id?
Any help is highly appreciated.
That is not possible. From the documentation:
If upsert is set to true and if no document matches the query
criteria, update() inserts a single document.
Then again, you write:
The result is some newly created documents
I hope that it's really only one document. With a query that contains only _id : {$in : [...]}, it wouldn't even insert a single document on my machine (MongoDB 2.5.0). It only inserts if I add more criteria. Could you check that again?
It's hard to come up with a meaningful definition of how this should behave. Combining $in can be tricky. Let's say you have two documents:
{ _id : 1, name : "John" }
{ _id : 2, name : "Jane" }
and you call
db.update({"_id" : {$in : [1,2]}, "name" : "Max"}, { ... }, { upsert: true});
What is supposed to happen? There is no document that has _id 1 or 2 and name equals "Max", so the upsert would have to insert... well, what? Maybe two documents with the name Max? If the array were larger, we'd create a ton of 'Max's which probably wasn't our intention (the semantics would be: "update one or insert a thousand", which is odd). So let's say we only insert one. But now, which _id to choose? And, of course, there is the problem that _id is a unique key, so in the example, both would fail.

Complex Active Record Association

User
first_name: "Johnny"
age: 15
Car
name: "Mazda"
Car
name: "BMW"
I would like results that look like
[ {"first_name": "Johnny", "age": 15, cars: [ { "name": "Mazda" }, { "name" : "BMW" } ] } ]
Is it possible to do this in Rails? So far I can get the Users car by typing johnny.cars but I'd like the data structure to also hold the values of the parent.
I was toying with the idea of using named_scopes and transient attributes but no luck so far any ideas/help is greatly appreciated.
You Could actually retrieve all the records from the other table using :includes statement
includes is magically syntax where in you can eager load all the assocaited records of a record.
Example In your case
User has_many cars
so If you do
#users = User.includes(:cars)
Now this would load all the user records and will eagerload all the cars records for each user objects
so if you loop through a user object and do
<% #users.each do |user| %>
<%= user.cars %>
<%end%>
user.cars wont fire a seperate query to fetch the all cars for the users instead it will fetch those record eager loaded using the includes clause
This technique is widely used to avoid N+1 query problem
Google for N+1 to know more on it
Hope this Help

Query with filtred fields for nested objected

lets say I've got a document
book: {name: "book",
"chapters":[{title: "Chapter I",
"sections":[{},{}]
}, {...}
]}
I what to get book object with embedded object chapters but each chapter should not contain nested "sections" (but should contain other attributes, like title):
book: {name: "Book",
"chapters":[{title: "Chapter I"
}, {...}
]}
How should I make a query using Mongo driver and Mongoid (or Mongomapper)?
I tried it with mongoid:
books.all[0].chapters.only(:title)[0].sections # it still works, though I expect sections to be nil
your query
books.all[0].chapters.only(:title)[0].sections
picks the books with all its chapter embedded documents on books.all, so there is no meaning to use 'only' after chapters. Your query can work if the chapters as a separate documents and got a has_many relationship instead embeds_many
So you have to use 'only' like this on books document
books.only('chapters.title').all[0].chapters.sections

Resources