I have the following grails domain class, containing a self-relationship.
class Message {
static hasMany = [replies: Message]
Message isReplyTo
User author
String title
String text
Date createdAt
Date lastUpdated
}
I want to write a query that can do two things
If a message is a parent, i.e it is not a reply to any other message, retrieve a list of messages that build a conversation starting with that message.
Message 1
---- Reply 1
---- Reply 2
-------- SubReply 1
Given a message that is a reply, to another message, also build a list same as above, including that parent that the given message (reply) falls under.
I have thought about this but can't quite think of a possible way of doing this, since there is no Conversations domain class that ties message belonging to the same conversation together. So I am hoping that there is some sort recursive query that would help me achieve this.
There are couple ways to handle this type of structure and there's no shortage of examples on the web about this type of tree based relationship.
In the simplest approach; you could have a Parent Child structure where a null parent would signal the top of the tree and a 'null' child would signal the end of that branch. This is a simple and effective structure but, it can be difficult to capture metrics because you'll always have to recursively search the entire thread.
Message{
...
Message parent
Message child
}
This post shows a good recursion in GSP example:
Another pattern for this is materialized path. It's a little trickery to implement but, easy to work once it's in place. Materialized paths are also much easier to collect metrics for like count of reply's and doing breadcrumbs are much easier too.
Message{
...
Message parent
String path //would like something like this: 1/2/3/4
}
For an example search of Materialized path check out google or this post.
Related
I have defined a HasMany relationsship in my Nova resource. Nova fires two requests when trying to load the children in the parent detail view:
1. GET /nova-api/childResources?viaResource=parentResources&viaResourceId=4711&viaRelationship=childResources&relationshipType=hasMany
-> This correctly returns the related records.
2. GET /nova-api/childResources/relate-authorization?viaResource=parentResources&viaResourceId=4711&viaRelationship=childResources&relationshipType=hasMany
-> This fails with a HTTP 500 returning Class name must be a valid object or a string.
Digging deeper into the underlying NovaRequest, I found out that all query params are gone inside the request. This is why viaResource cannot be used to instantiate a class and to above error occurs.
I have no idea, what could cause this.
Turned out, the problem originated from an incomplete nginx configuration. I wasn’t passing the query string to PHP.
My Content structure is:
-Home (the site root node)
-About Us
-Our Sevice1
-Our Sevice2
-Our Sevice3
I created a macro for Our Services.
In macro, I want Our Sevice1, Our Sevice2, Our Sevice3...
But in the list variable About Us also come but I don't want it
I want only our service name of the child node
var list= CurrentPage.Children();
About Us also come on the list but I don't want it.
The reason that you see the About Us page in the collection is because you use the Children method.
With the Children method you ask for the direct child nodes of a parent node traversing one level down. So in this case you ask for all direct children of the home page so this works like expected.
What you are trying to achieve is a collection of of all Service nodes. To accomplish this you could do something like this.
Make sure that you have a seperated Document Type for your service nodes ( like for example doc type Service Page ).
Then you can do the following:
var servicePages = CurrentPage.ServicePages;
You can view the docs about it here:
https://our.umbraco.org/documentation/reference/querying/dynamicpublishedcontent/collections
But all of this is using dynamic syntax, this will be removed in future versions of Umbraco. So I suggest you go and use the strongly type syntax.
Then this can be changed by:
var servicePages = Model.Content.Children.Where(x => x.DocmentTypeAlias == "servicePage");
What this does is take the IPublishedContent object of the current page you are on, which is the Home Page then you take all children which has a document type alias of type servicePage.
Like #Mivaweb mentioned, it's better to not use dynamics (I think for performance in addition to being removed in the future).
However, I don't think you have to create a separate doc type, although that will work too. The predicate for the Where method should handle other expressions such as:
var servicePages = Model.Content.Children.Where(x => x.Name.StartsWith("Our Sevice"));
This my project code I want to save my data into database.
def save(){
List<Employee> list = Employee.findAllById(session.getAttribute("empId"))
Milestone milestone = new Milestone()
milestone.setMilestone_Date(params.milestone_Date)
milestone.setMilestone_Name(params.milestone_Name)
milestone.setMilestone_Description(params.milestone_Description)
milestone.save()
EmployeeMilestone employeeMilestone=new EmployeeMilestone()
Employee employee = list.get(0)
employeeMilestone.setEmployee(employee)
employeeMilestone.setMilestone(milestone)
employeeMilestone.save()
[employeeMilestones:employeeMilestone]
}
I am getting this error
Error 500: Internal Server Error URI /ProjectTrackerMain/milestone/save Class java.lang.IndexOutOfBoundsException Message Index: 0, Size: 0
You didn't actually ask a question, so this may be a bit vague!
An IndexOutOfBoundsException happens when you try to access something from a collection in a location where there is no "something". For example, maybe you asked for the tenth element in a list, but there are only two. In your case, you're asking for the zeroth (in plain English, "First") element on this line of code:
Employee employee = list.get(0)
and presumably the list is empty. Your error message says "Size: 0". You can't get the first element from a list that has zero elements in it, so that's an index out of bounds exception.
Why is your list 0? That's a different question. You might try printing out
session.getAttribute("empId")
to see if your employee ID is what you expected. You might also look at the data in your database to see if you actually managed to save an employee! One way or another, you're not getting the data you expected, and then you're trying to use it.
In general, using a debugger to look at your elements, or just using "println" along the way to look at values is helpful in debugging problems like this. That way, you'll find out on line 1 that your list of Employees is not what you expected, instead of several lines later when you try to use it!
I have 3 domains: A, B, C.
A and C have many-to-many relationship through B.
A and C are searchable.
When I search and get list of A domain all the fields in A are accessible, however relation field is always 'null'. Why I can't access relational field? Why do I get 'null'? If I access object directly, I see a relation, but when searchable returns A domain, I get 'null' on a relation field.
P.S: I tried to make B searchable but it looks like searchable having issue with indexing it on top of that I don't see any point in indexing B since it exists for the sake of many-to-many relationship only.
Please I need help with it. I need to be able to get to C via A on a searchable return.
Thank you.
[Update]: I made a prototype project today (small DB) and made domain B searchable. Now I can access relational field. However in my real project, I don't want to make B searchable since database is big and indexing takes too long. Is there a way around it?
You can refrash all instance in result list or use reload:true property for seach method
searchableService.search(query,[reload:true])
You can find full list of options: http://grails.org/Searchable+Plugin+-+Methods+-+search
reload - If true, reloads the objects from the database, attaching them to a Hibernate session, otherwise the objects are reconstructed from the index. Default is false
Ok, I believe I solved my issue.
First checkout link to a similar question: Grails searchable plugin -- Please give GalmWing some credit.
My solution is following, I am implementing my own controller and following piece of code implements searchable service call:
if (params.q) {
try{
def searchResults = searchableService.search(params.q, params)
searchResults.results.each {
it.refresh()
}
return [carInstanceList:searchResults.results, carInstanceTotal:searchResults.total]
} catch (SearchEngineQueryParseException ex) {
return [parseException: true]
}
As you can see I have a loop where on each item of domain "A" I do refresh. Now refresh gets real record from DB with all the links. Now I return list into GSP and it extracts all of "C" domains associated with the "A" domain.
Now this way you might get performance penalty, but in my case searchable is actually not able to index "B" domain, it is working for a while and then crashes, so I don't have another choice, at least for now.
I have two object, a room type and a reservation. Simplified they are:
class Room {
String description
int quantity
}
class Reservation {
String who
Room room
}
I want to query for all rooms along with the number of rooms available for each type. In SQL this does what I want:
select id, quantity, occupied, quantity-coalesce(occupied, 0) as available
from room left join(select room_id, count(room_id) as occupied from reservation)
on id = room_id;
I'm not getting anywhere trying to work out how to do this with HQL.
I'd appreciate any pointers since it seems like I'm missing something fairly fundamental in either HQL or GORM.
The problem here is your trying to represent fields that are not your domain classes like available and occupied. Trying to get HQL\GORM to do this can be a bit a little frustrating, but not impossible. I think you have a couple options here...
1.) Build your domain classes so that there easier to use. Maybe your Room needs to know about it's Reservations via a mapping table or, perhaps write what you want the code to look like and then adjust the design.
For example. Maybe you want your code to look like this...
RoomReservation.queryAllByRoomAndDateBetween(room, arrivalDate, departureDate);
Then you would implement it like this...
class RoomReservation{
...
def queryAllByRoomAndDateBetween(def room, Date arrivalDate, Date departureDate){
return RoomReservation.withCriteria {
eq('room', room)
and {
between('departureDate', arrivalDate, departureDate)
}
}
}
2.) My second thought is... It's okay to use the database for what it's good for. Sometimes using sql in you code is simply the most effective way to do something. Just do it in moderation and keep it centralized and unit tested. I don't suggest you use this approach because you query isn't that complex, but it is an option. I use stored procedures for things like 'dashboard view's' that query millions of objects for summary data.
class Room{
...
def queryReservations(){
def sql = new Sql(dataSoruce);
return sql.call("{call GetReservations(?)}", [this.id]) //<-- stored procedure.
}
}
I'm not sure how you can describe a left join with a subquery in HQL. INn any case you can easily execute raw SQL in grails too, if HQL is not expressive enough:
in your service, inject the dataSource and create a groovy.sql.Sql instance
def dataSource
[...]
def sql= new Sql(dataSource)
sql.eachRow("...."){row->
[...]
}
I know it's very annoying when people try to patronize you into their way of thinking when you ask a question, instead of answering your question or just shut up, but in my opinion, this query is sufficiently complex that I would create a concept for this number in my data structure, perhaps an Availability table associated to the Room, which would keep count not only of the quantity but also of the occupied value.
This is instead of computing it every time you need it.
Just my $.02 just ignore it if it annoys you.