I have something like this in RavenDb:
Path [hasMany] Goals [hasMany] Achievements
So I have one document that contains goals and achievements.
If it where a traditional database, I could make this query
select g.id, count(a.id)
from path p
join goals g on p.id = g.pathId
join achievement a on a.id = g.id
group by goal.id
How do I do this query in ravendb?
Right now I'm doing it like this:
Path path = RavenSession.Load<Path>(pathId);
path.Goals.Select(x => new
{
Id = x.Id,
Name = x.Name,
TOnCourse = x.Achievements.Where(y => y.Resolution == Resolution.OnCourse).Count(),
TAstray = x.Achievements.Where(y => y.Resolution == Resolution.Astray).Count()
});
I don't want to do it this way, because I think that I'm loading all the "Goals" and "Achievements" and what I only want is to make the aggregation in the DB (ravendb)
If you want to know what Path, Goals and Achievements really are in my model here is my "pet" project http://dpath.apphb.com/
EDIT
I think I will get those "calculated" values and put them in Goal as properties, because I think the calculation is going to be very common, so keeping it simple since an achievement cannot be deleted, and the user will have a "relation" with goal and the quantity of achievements in order to get "My Stats"
Nevertheless, I would like to know how would you accomplish that query in RavenDb
Thanks!
You are loading just a single document for this, so that is likely to not be an issue.
You aren't loading anything else.
You can do this in an index, and then load the stored fields from there, but I don't think you need this unless your document is very large.
Related
I've got a few tables, Deployment, Deployment_Report and Workflow. In the event that the deployment is being reviewed they join together so you can see all details in the report. If a revision is going out, the new workflow doesn't exist yet new workflow is going into place so I'd like the values to return null as the revision doesn't exist yet.
Complications aside, this is a sample of the SQL that I'd like to have run:
DECLARE #WorkflowID int
SET #WorkflowID = 399 -- Set to -1 if new
SELECT *
FROM Deployment d
LEFT JOIN Deployment_Report r
ON d.FSJ_Deployment_ID = r.FSJ_Deployment_ID
AND r.Workflow_ID = #WorkflowID
WHERE d.FSJ_Deployment_ID = 339
The above in SQL works great and returns the full record if viewing an active workflow, or the left side of the record with empty fields for revision details which haven't been supplied in the event that a new report is being generated.
Using various samples around S.O. I've produced some Entity to SQL based on a few multiple on statements but I feel like I'm missing something fundamental to make this work:
int Workflow_ID = 399 // or -1 if new, just like the above example
from d in context.Deployments
join r in context.Deployment_Reports.DefaultIfEmpty()
on
new { d.Deployment_ID, Workflow_ID }
equals
new { r.Deployment_ID, r.Workflow_ID }
where d.FSJ_Deployment_ID == fsj_deployment_id
select new
{
...
}
Is the SQL query above possible to create using LINQ to Entities without employing Entity SQL? This is the first time I've needed to create such a join since it's very confusing to look at but in the report it's the only way to do it right since it should only return one record at all times.
The workflow ID is a value passed in to the call to retrieve the data source so in the outgoing query it would be considered a static value (for lack of better terminology on my part)
First of all don't kill yourself on learning the intricacies of EF as there are a LOT of things to learn about it. Unfortunately our deadlines don't like the learning curve!
Here's examples to learn over time:
http://msdn.microsoft.com/en-us/library/bb397895.aspx
In the mean time I've found this very nice workaround using EF for this kind of thing:
var query = "SELECT * Deployment d JOIN Deployment_Report r d.FSJ_Deployment_ID = r.Workflow_ID = #WorkflowID d.FSJ_Deployment_ID = 339"
var parm = new SqlParameter(parameterName="WorkFlowID" value = myvalue);
using (var db = new MyEntities()){
db.Database.SqlQuery<MyReturnType>(query, parm.ToArray());
}
All you have to do is create a model for what you want SQL to return and it will fill in all the values you want. The values you are after are all the fields that are returned by the "Select *"...
There's even a really cool way to get EF to help you. First find the table with the most fields, and get EF to generated the model for you. Then you can write another class that inherits from that class adding in the other fields you want. SQL is able to find all fields added regardless of class hierarchy. It makes your job simple.
Warning, make sure your filed names in the class are exactly the same (case sensitive) as those in the database. The goal is to make a super class model that contains all the fields of all the join activity. SQL just knows how to put them into that resultant class giving you strong typing ability and even more important use-ability with LINQ
You can even use dataannotations in the Super Class Model for displaying other names you prefer to the User, this is a super nice way to keep the table field names but show the user something more user friendly.
I have the following tables, User, Project and Images.
A User has a one to many relationship with Projects and Images. Each Project and Image is owned by a User.
A Project has a many to many relationship with Images. So each Project can have many Images, and an Image can appear within many Projects.
I want to write a DQL query to get all Images, for a specific User that are not included in any Projects. This I can write in SQL.
Is writing in SQL the best way to go?
Or should I be using DQL to do this?
I have tried writing the DQL but its hard work!
Edit
From within my Image Repo I am now doing this
$qb = $this->createQueryBuilder("i");
$qb->select("i")
->from('MyBundleName:User','u')
->innerJoin('u.images', 'user_images')
->where('IDENTITY(u.id) = :user_id')
->andWhere('NOT EXISTS (
SELECT p
FROM MyBundleName:Project p
WHERE user_images MEMBER of p.images
)')
->setParameter('user_id', $user_id);
I have replace the / syntax with : for my classes as they failed when using /
I am still getting this error though;
[Semantical Error] line 0, col 131 near 'id) = :user_id': Error:
Invalid PathExpression. Must be a SingleValuedAssociationField.
The function createQueryBuilder requires an alias, I am passing it "i" - is that right?
I then give it "i" again when calling select?
If I remove the innerJoin then it works, but the results are wrong. It returns all images even if they do exist within an project.
I can't say how difficult it would be in DQL, but I can tell you that in SQL it sounds pretty simple:
SELECT I.*
FROM IMAGES I
INNER JOIN USERS U ON (I.USER_ID = U.USER_ID)
WHERE NOT EXISTS (
SELECT *
FROM PROJECTS P, PROJECT_IMAGES PI
WHERE P.USER_ID = U.USER_ID
AND PI.PROJECT_ID = P.PROJECT_ID
AND I.IMAGE_ID = PI.IMAGE_ID
)
Images owned by a user which does not exist in any project that the user owns.
I don't know what your entities look like but given the relations something like this should work. The key is combining NOT EXISTS and MEMBER OF (you want to make sure that for all returned images no project exists that the image is a member of).
$qb->select("i")
->from('MyBundle\Entity\User','u')
->innerJoin('u.images','i')
->where('IDENTITY(u) = :user_id')
->andWhere('NOT EXISTS (
SELECT p
FROM MyBundle\Entity\Project p
WHERE i MEMBER of p.images
)')
->setParameter('user_id', $user_id);
This is a question asked with an ignorance of thew subject matter, but i have searche dlong and hard so i hope this will not be too painful.
I'm using nhibernate for a many to many query.
My objects map (not my design, not getting changed any time soon):
Computer (id, name, etc...) -> (mapping table ) -> Config ( id, key, value )
One computer may have many configs, any config may belong to multiple computers. i can read a computer out fine and the list(bag) member is populated fine.
I then want to find a computer that has numerous configs.
E.g. all computers that have:
OS : Windows
CPU : 2GHz
etc.
Any assistance on how I could put this into a criteria query would be greatly appreciated. I've done some of the basics but wrapping my head around this is proving hard work.
Cheers for any assistance,
Rob.
If the parameters are always the same, use a query like the following:
var computers = session.CreateQuery(
#"select c
from Computer c
inner join c.Configurations as osconfig
inner join c.Configurations as cpuconfig
where
osconfig.Name = 'OS'
and osconfig.Value = :os
and cpuconfig.Name = 'CPU'
and cpuconfig.Value = :cpu")
.SetString("os", "Windows")
.SetString("cpu", "2GHz")
.List<Computer>();
If you mapped it as a map, you can even do something like this:
var computers = session.CreateQuery(
#"select c
from Computer c
where
c.Configurations['OS'] = :os
and c.Configurations['CPU'] = :cpu")
.SetString("os", "Windows")
.SetString("cpu", "2GHz")
.List<Computer>();
If the parameters are always different, use criteria to add them dynamically.
I'm trying to a LINQ query, and I have been stumped for some time. I tried looking up the documentation, and around here, but I can't quite seem to find enough pieces to make the whole thing.
If I were to be writing this in SQL, the query would be
SELECT *
FROM (Person JOIN Event ON Person.ID = Event.PersonID) as t
Where (Event.Type = "Invitation") AND !Exists(SELECT *
FROM Event
WHERE Event.Type = "Something"
AND Event.Conference = "someString"
AND t.ID = Event.PersonID)
Any input would be greatly appreciated, even if you only have a solution for part.
Your Event table appears to have a foreign key to Person. This seems unusual as it would imply that an Event can only have one person. I'm going to assume that your Event table is the many-many table in this model. Assuming you have an association between People and Events (PeopleEvents?), you should be able to do this with something like the following (using !Any in place of !Exists):
from person in People
from event in person.Events
where event.Type == "Invitation" &&
!person.Events.Any(event => event.Type == "Something" && event.Conference == "someString")
select new {person, event}
(note, you may want to project into some other structure here rather than projecting the select many I'm showing here.) If we had more information about your model or what you are trying to accomplish, we might be more help.
I have rails controller coding as below:
#checked_contact_ids = #list.contacts.all(
:conditions => {
"contacts_lists.contact_id" => #list.contacts.map(&:id),
"contacts_lists.is_checked" => true
}
).map(&:id)
its equivalent to sql
SELECT *
FROM "contacts"
INNER JOIN "contacts_lists" ON "contacts".id = "contacts_lists".contact_id
WHERE ("contacts_lists".list_id = 67494 )
This above query takes more time to run, I want another way to run the same query with minimum time.
Is anyone knows please notice me Or is it possible? or is the above query enough for give output?
I am waiting information...................
I think the main problem with your original AR query is that it isn't doing any joins at all; you pull a bunch of objects out of the database via #list.contacts and then throw most of that work away to get just the IDs.
A first step would be to replace the "contacts_lists.contact_id" => #list.contacts.map(&:id) with a :joins => 'contact_lists' but you'd still be pulling a bunch of stuff out of the database, instantiating a bunch of objects, and then throwing it all away with the .map(&:id) to get just ID numbers.
You know SQL already so I'd probably go straight to SQL via a convenience method on your List model (or whatever #list is), something like this:
def checked_contact_ids
connection.execute(%Q{
SELECT contacts.id
FROM contacts
INNER JOIN contacts_lists ON contacts.id = contacts_lists.contact_id
WHERE contacts_lists.list_id = #{self.id}
AND contacts_lists.is_checked = 't'
}).map { |r| r['id'] }
end
And then, in your controller:
#checked_contact_ids = #list.checked_contact_ids
If that isn't fast enough then review your indexes on the contacts_lists table.
There's no good reason not go straight to SQL when you know exactly what data you need and you need it fast; just keep the SQL isolated inside your models and you shouldn't have any problems.