I'm using Symfony 3.4 and its doctrine querybuilder. I have an entity Ad that has different options in a one too many relation. Therefore I'm building a filter.
$optionIds is a array with multiple integers representing the option.id
I have the following filter:
$query->leftJoin('ad.options', 'opt')
->andWhere($query->expr()->in('opt.id', ':optionIds'))
->setParameter('optionIds', $optionIds)
Problem with this filter is dat it returns all ads that have one of the options linked. The idee is to get only the ads that have all id's linked. So this filter is a OR instead-off an AND filter?
Second issue is that it return multiple time the same ad if it matches multiple options ids. I don't want to use groupBy to solve this agina.
I also change the code to the following:
$cnt = 0;
foreach ($optionIds as $optionId) {
$query->leftJoin('ad.options', 'opt'.$cnt)
->andWhere('opt'.$cnt.'.id = :id'.$cnt)
->setParameter('id'.$cnt++, $optionId);
}
This works but is very slow.
Help is appreciated, i'm stuk already half a day!
To check if all options should exist for the ad you will need to use aggregation and filter on aggregated result
$query->addSelect('COUNT(DISTINCT opt.id) AS total_options')(
->leftJoin('ad.options', 'opt')
->andWhere($query->expr()->in('opt.id', ':optionIds'))
->addGroupBy('ad.id')
->having('total_options = '.count($optionIds))
->setParameter('optionIds', $optionIds)
For reference and more details see my other answers for similar situation in a many to many relation
Symfony2 - Doctrine2 QueryBuilder WHERE IN ManyToMany field
Sql/Doctrine query to find data with multiple condition with Many to Many associations
Related
Not being a SQL expert, and discovering Metabase here, so please be kind;
I'm working on a dashboard that would offer a specific filter.
For the sakes of clarity, I'll describe my simplified case.
I have some projects in my DB. Some are "active", some aren't. I would like to create a filter that provides only a selection of those "active".
Because my project settings are in a different table than the project itself, here's basically how I've tried to create this filter:
SELECT "public"."Project"."status" AS "status", "ProjectSettings"."name" AS "ProjectSettings__name"
FROM "public"."Project"
LEFT JOIN "public"."ProjectSettings" "ProjectSettings" ON "public"."Project"."id" = "ProjectSettings"."projectId"
WHERE (
"ProjectSettings"."active" = 'ACTIVE')
AND "ProjectSettings"."name" = {{Project}}
What I was expecting to happen here is that only the filtered active projects were made available in my filter. Without any luck so far.
Thanks for your suggestions :)
I assume {{Projects}} is a collection of multiple projects. Is that correct? if so, you should use an IN clause in the criterion.
WHERE (
"ProjectSettings"."active" = 'ACTIVE')
AND "ProjectSettings"."name" IN {{Project}}
the listing {{Projects}} should then be in the form 'project1','project2','project3',...
I have updated this question
I have the following SQL scope in a RAILS 4 app, it works, but has a couple of issues.
1) Its really RAW SQL and not the rails way
2) The string interpolation opens up risks with SQL injection
here is what I have:
scope :not_complete -> (user_id) { joins("WHERE id NOT IN
(SELECT modyule_id FROM completions WHERE user_id = #{user_id})")}
The relationship is many to many, using a join table called completions for matching id(s) on relationships between users and modyules.
any help with making this Rails(y) and how to set this up to take the arg of user_id with out the risk, so I can call it like:
Modyule.not_complete("1")
Thanks!
You should have added few info about the models and their assocciation, anyways here's my trial, might have some errors because I don't know if the assocciation is one to many or many to many.
scope :not_complete, lambda do |user_id|
joins(:completion).where.not( # or :completions ?
id: Completion.where(user_id: user_id).pluck(modyule_id)
)
end
PS: I turned it into multi line just for readability, you can change it back to a oneline if you like.
I have been trying to figure out how to perform specific query for quite a while, and have been through several attempts to no avail. Below is an example to illustrate the problem:
There are 2 types of nodes, users and documents. Users can have a relationship type labeled collaborates_with, and can be related to documents as can_edit, created, or have no relationship.
Now what I would like to do is perform a query that will return all documents that fit a set of search criteria (say created within the last week), AND if the document was created by a collaborator of a specific user, return that relationship.
To fetch the documents and the creator of each document, the query is pretty straight forward:
MATCH (doc:document)<-[rel:created]-(u1:user)
WHERE doc.createddate > TIMESTAMP_FOR_ONE_WEEK_AGO
RETURN doc, u1
where TIMESTAMP_FOR_ONE_WEEK_AGO is just the unix timestamp corresponding to right now minus 7*24*60*60*1000.
The difficulty comes when trying to conditionally return the relationship with the current user.
I have played with CASE statements and OPTIONAL MATCH, but nothing seems to get what I'm looking for. One example of my attempts:
MATCH (doc:document)<-[rel:created]-(u1:user)
WHERE doc.createddate > TIMESTAMP_FOR_ONE_WEEK_AGO
WITH doc, u1
MATCH u1-[rel:collaborates_with]-(me:user)
WHERE me.username = MY_USERNAME
RETURN doc, rel
This, however, only returns the documents that have been created by one of my collaborators. Instead, I'd like it to return ALL of the documents fitting the search, and only return the relationship if it exists.
Has anyone been able to perform something like this?
NOTE: This question is similar, but not quite what I'm running into.
Optional Match should do it:
MATCH (doc:document)<-[rel:created]-(u1:user)
WHERE doc.createddate > TIMESTAMP_FOR_ONE_WEEK_AGO
WITH doc, u1 //find all docs that satisfy search conditions
OPTIONAL MATCH u1-[rel:collaborates_with]-(me:user) //optionally see if the creator collaborates with me
WHERE me.username = MY_USERNAME
RETURN doc, rel
In rails 3, I would like to do the following:
SomeModel.where(:some_connection_id => anArrayOfIds).select("some_other_connection_id")
This works, but i get the following from the DB:
[{"some_other_connection_id":254},{"some_other_connection_id":315}]
Now, those id-s are the ones I need, but I am uncapable of making a query that only gives me the ids. I do not want to have to itterate over the resulst, only to get those numbers out. Are there any way for me to do this with something like :
SomeModel.where(:some_connection_id => anArrayOfIds).select("some_other_connection_id").values()
Or something of that nautre?
I have been trying with the ".select_values()" found at Git-hub, but it only returns "some_other_connection_id".
I am not an expert in rails, so this info might be helpful also:
The "SomeModel" is a connecting table, for a many-to-many relation in one of my other models. So, accually what I am trying to do is to, from the array of IDs, get all the entries from the other side of the connection. Basicly I have the source ids, and i want to get the data from the models with all the target ids. If there is a magic way of getting these without me having to do all the sql myself (with some help from active record) it would be really nice!
Thanks :)
Try pluck method
SomeModel.where(:some => condition).pluck("some_field")
it works like
SomeModel.where(:some => condition).select("some_field").map(&:some_field)
SomeModel.where(:some_connection_id => anArrayOfIds).select("some_other_connection_id").map &:some_other_connection_id
This is essentially a shorthand for:
results = SomeModel.where(:some_connection_id => anArrayOfIds).select("some_other_connection_id")
results.map {|row| row.some_other_connection_id}
Look at Array#map for details on map method.
Beware that there is no lazy loading here, as it iterates over the results, but it shouldn't be a problem, unless you want to add more constructs to you query or retrieve some associated objects(which should not be the case as you haven't got the ids for loading the associated objects).
I use jqGrid to display data which is retrieved using NHibernate. jqGrid does paging for me, I just tell NHibernate to get "count" rows starting from "n".
Also, I would like to highlight specific record. For example, in list of employees I'd like a specific employee (id) to be shown and pre-selected in table.
The problem is that this employee may be on non-current page. E.g. I display 20 rows from 0, but "highlighted" employee is #25 and is on second page.
It is possible to pass initial page to jqGrid, so, if I somehow use NHibernate to find what page the "highlighted" employee is on, it will just navigate to that page and then I'll use .setSelection(id) method of jqGrid.
So, the problem is narrowed down to this one: given specific search query like the one below, how do I tell NHibernate to calculate the page where the "highlighted" employee is?
A sample query (simplified):
var query = Session.CreateCriteria<T>();
foreach (var sr in request.SearchFields)
query = query.Add(Expression.Like(sr.Key, "%" + sr.Value + "%"));
query.SetFirstResult((request.Page - 1) * request.Rows)
query.SetMaxResults(request.Rows)
Here, I need to alter (calculate) request.Page so that it points to the page where request.SelectedId is.
Also, one interesting thing is, if sort order is not defined, will I get the same results when I run the search query twice? I'd say that SQL Server may optimize query because order is not defined... in which case I'll only get predictable result if I pull ALL query data once, and then will programmatically in C# slice the specified portion of query results - so that no second query occur. But it will be much slower, of course.
Or, is there another way?
Pretty sure you'd have to figure out the page with another query. This would surely require you to define the column to order by. You'll need to get the order by and restriction working together to count the rows before that particular id. Once you have the number of rows before your id, you can figure what page you need to select and perform the usual paging query.
OK, so currently I do this:
var iquery = GetPagedCriteria<T>(request, true)
.SetProjection(Projections.Property("Id"));
var ids = iquery.List<Guid>();
var index = ids.IndexOf(new Guid(request.SelectedId));
if (index >= 0)
request.Page = index / request.Rows + 1;
and in jqGrid setup options
url: "${Url.Href<MyController>(c => c.JsonIndex(null))}?_SelectedId=${Id}",
// remove _SelectedId from url once loaded because we only need to find its page once
gridComplete: function() {
$("#grid").setGridParam({url: "${Url.Href<MyController>(c => c.JsonIndex(null))}"});
},
loadComplete: function() {
$("#grid").setSelection("${Id}");
}
That is, in request I lookup for index of id and set page if found (jqGrid even understands to display the appropriate page number in the pager because I return the page number to in in json data). In grid setup, I setup url to include the lookup id first, but after grid is loaded I remove it from url so that prev/next buttons work. However I always try to highlight the selected id in the grid.
And of course I always use sorting or the method won't work.
One problem still exists is that I pull all ids from db which is a bit of performance hit. If someone can tell how to find index of the id in the filtered/sorted query I'd accept the answer (since that's the real problem); if no then I'll accept my own answer ;-)
UPDATE: hm, if I sort by id initially I'll be able to use the technique like "SELECT COUNT(*) ... WHERE id < selectedid". This will eliminate the "pull ids" problem... but I'd like to sort by name initially, anyway.
UPDATE: after implemented, I've found a neat side-effect of this technique... when sorting, the active/selected item is preserved ;-) This works if _SelectedId is reset only when page is changed, not when grid is loaded.
UPDATE: here's sources that include the above technique: http://sprokhorenko.blogspot.com/2010/01/jqgrid-mvc-new-version-sources.html