RedisGraph / redisgraph-go

A Golang client for redisgraph
https://redisgraph.io
BSD 3-Clause "New" or "Revised" License
132 stars 38 forks source link

How do you iterate over query results in view #18

Closed AppyCat closed 5 years ago

AppyCat commented 5 years ago

Hi, I'm using the Go Buffalo framework. I'm setting a query result for the view, however the result format does not fit how the view consumes it. Here's my code:

query := MATCH (p:person)-[v:visited]->(c:country) RETURN p.name, p.age, v.purpose, c.name rs, _ := graph.Query(query) rs.PrettyPrint() c.Set("rs", rs)

And the view:

<%= for (r) in rs { %>

<%= r.p.name %> <%= r.p.age %> <%= r.p.status %> <%= r.v.purpose %> <%= r.c.name %>

<% } %>

What is the correct way to output the result in an html view with the Go lang driver?

swilly22 commented 5 years ago

Hi @AppyCat, please see the update readme file, it shows how to iterator over a result set.

AppyCat commented 5 years ago

Thank you, I tried that in the view, it throws an error. Here's the code for view and error:

<%= for rs.Next() { %> <%= r := rs.Record() %>

<%= r.GetByIndex(0).(string) %>

<% } %>

index.html: line 0: expected next token to be (, got IDENT instead line 42: no prefix parse function for : found line 42: no prefix parse function for = found line 45: no prefix parse function for DOT found

swilly22 commented 5 years ago

Can you please share the query you're executing, I have a feeling there's a syntax error, please make sure you're checking returned error from graph.query

swilly22 commented 5 years ago

In addition would you mind sharing your usecase on https://github.com/RedisGraph/RedisGraph/issues/677 Thank you!

AppyCat commented 5 years ago

Thanks, here's the query, it pretty prints out fine:

query := MATCH (p:person)-[v:visited]->(c:country) RETURN p.name, p.age, v.purpose, c.name rs, _ := graph.Query(query) rs.PrettyPrint() c.Set("rs", rs) // adds to context to pass to view

The use case is for a match making app for recommendations. Am trying to get basics working before applying the schema.

swilly22 commented 5 years ago

I see, can you please try printing the result-set using the next iterator to the console?

AppyCat commented 5 years ago

I think we got to the heart of it :) Here's the error on:

rs.Next().PrettyPrint()

actions/home.go:75:4: rs.Next undefined (type *redisgraph.QueryResult has no field or method Next)

swilly22 commented 5 years ago

Next returns a Record object, which doesn't have a PrettyPrint method, on a Record you can use the Get* methods

AppyCat commented 5 years ago

I've used Get methods in the view, however the problem is the error states the query result has no field or method Next().

Here's my output just using:

rs2 := rs.Next() // as a test

rs.Next undefined (type *redisgraph.QueryResult has no field or method Next)

AppyCat commented 5 years ago

I tried the example on the Github page in a fresh stand alone file, and still get same error on the Next():

./main.go:51:8: rs.Next undefined (type redisgraph.QueryResult has no field or method Next) ./main.go:53:10: rs.Record undefined (type redisgraph.QueryResult has no field or method Record)

AppyCat commented 5 years ago

Without this code, the example on the readme outputs just fine:

for rs.Next() { // Get current record. r := rs.Record()

    p_name := r.GetByIndex(0).(string)
    p_age := r.GetByIndex(1).(int)
    c_name := r.GetByIndex(2).(string)
    fmt.Printf("p_name: %s p_age: %d c_name: %s\n", p_name, p_age, c_name)
}
swilly22 commented 5 years ago

Please make sure you're using the latest version of redisgraph-go as this API been merged earlier today, I'll suggest removing the library locally and refetching

swilly22 commented 5 years ago

@AppyCat I've just tagged master as V2.0.1 Please let me know if you're able to use the new Result-Set consumption API

AppyCat commented 5 years ago

Thank you for following up. I am able to get the complete result now from Next() in a different app but just need to figure out the syntax on the template used in the Echo library.

{{range .rs}} {{.rs := .rs.Record()}} {{.rs.Record.GetByIndex(0).(string)}}
{{end}}

Perhaps it may be an idea to save the above in the function as a slice or map, and send that to the view? The logic works in the function, but its not in harmony with some view template libs.

swilly22 commented 5 years ago

Unfortunately I'm not familiar with Echo in my mind it would be worthwhile getting the template syntax right and avoid the double processing and the extra memory overhead of saving the result-set to another slice/map.

AppyCat commented 5 years ago

Unfortunately the template lib is very limited in functionality, it won't work with a for loop nor likes Record(), throws an error on the parenthesis. It takes range, but that doesn't work for the output logic.

AppyCat commented 5 years ago

Thank you for your help but I am losing too much time on this now. Its not ideal to put format logic in the view as below, it breaks any MVC separation of concerns. It may be an idea to add a view consumption friendly function to the driver and testing it in the go standard library template using just range.

for rs.Next() { r := rs.Record() p_name := r.GetByIndex(0).(string) p_age := r.GetByIndex(1).(int) c_name := r.GetByIndex(2).(string) fmt.Printf("p_name: %s p_age: %d c_name: %s\n", p_name, p_age, c_name) }

The rest of the driver functionality is quite smooth and simple.

swilly22 commented 5 years ago

Alright, can I close this issue?

AppyCat commented 5 years ago

I tried the Ruby driver as a comparison, it gives the result as:

cmd = """MATCH (p:person)-[:works]->(e:employer) RETURN p""" response = r.query(cmd) @res = response.resultset

And I got the view working as:

<% @res.each do |r| %> <%= r[0][0]["name"] %> <%= r[0][1]["age"] %>
<% end %>

Would it be possible to add a method such as 'resultset' in the Ruby driver?

I'll do a comparison with Neo4j tomorrow.

The problem may be in Redisgraph itself not providing a better structured result by default or options for different output formats.

AppyCat commented 5 years ago

Upon reflection I don't think its realistic to put this code in a view file as many view templates by design have limited functionality.

{{ for rs.Next() }} {{ r := rs.Record() }} {{ r.GetByIndex(0).(string) }} {{ r.GetByIndex(1).(int) }} {{ c_name := r.GetByIndex(2).(string) }} {{ end }}

The above example croaks on any of the parenthesis.

AppyCat commented 5 years ago

I created a slice to use in the view to solve above issue and will put it below in case helpful to anyone else:

type person struct { name string age int status string country string }

people := []person{}

for rs.Next() { r := rs.Record() people = append(people, (person{name: r.GetByIndex(0).(string), age: r.GetByIndex(1).(int), status: r.GetByIndex(2).(string), country: r.GetByIndex(3).(string)})) }

Then pass off people slice to view.