loopbackjs: how to get specifics parents filtering related model - loopbackjs

like a common joined relation i would like to filter my results based on filtered children in a parent-child relation.
i did this
{"include":{"relation":"children","scope":{"where":{"and":[{"name":"xxx"}]}}}}
that gave me ALL parents and inside them, children filtered by that name.
any clues? thanks
ref:
https://docs.strongloop.com/display/public/LB/Querying+related+models#Queryingrelatedmodels-Usingfiltersparameterswithincludedrelations

As per https://stackoverflow.com/a/32933383/344022 there's nothing officially available yet. There is a fork of the loopback-connector by #DiogoDoreto that does attempt to provide it. I haven't tried it, but if you were to use it you would do the following in a filter:
"where": {
"children": {
"where": {
"name": "xxx"
}
}
}

Related

Loopback where filter not working inside include

I have this filter written that i am passing to my endpoint written in Loopbackjs.
const filter = {
where: { status: { neq: "processed" } },
include: [
{ relation: "vendor", scope: { fields: ["id", "name"] } },
{
relation: "pickupLocation",
scope: { where: { cityId: "5ee134da0138634c27a6e1dd" } },
},
],
limit: 200,
skip: 0
};
return this.http.get<IPickupRequest[]>(
`${environment.url}/PickupRequests?filter=${encodeURIComponent(
JSON.stringify(filter)
)}`
);
The pickupRequest collection contains a belongsTo relation to pickupLocation collection. The pickupLocation collection contains a property called cityId on which i am trying to apply a where clause but it does not work. Moreover I also want to get the fields of pickupLocation too inside the pickupRequest object so that i cna use them in my table. The simple include works perfectly and shows the data as desired but when where clause is applied it just doesn't work and also shows only pickupRequest object but does not include pickupLocation data inside it. Moreover since i am using pagination I need it to return me exactly 200 records each time. Am i doing something wrong? What is the exact issue here? I am using Loopback 3
Here, you are expecting that where filter applied on the pickupLocation relation would act something similar to SQL's inner join. However, in loopback, whenever you do an include in the query, the framework internally makes two separate queries on collections or tables of each of those models and combine them; effectively making it work like SQL's left outer join. So, in the above query PickupRequest list will have all object, irrespective of where filter on pickupLocation model. The pickupLocation relation would be present only in those PickupRequest records where cityId = "5ee134da0138634c27a6e1dd" and remaining places, the relation would be an null object.
To overcome this problem, I would say, make your primary query on pickupLocation model as per the { cityId: "5ee134da0138634c27a6e1dd" } where filter and do an include of PickupRequest model.

Return join table attributes in incluce with loopback

I've got a data structure fairly similar to the one described on the Loopback HasManyThrough documentation page.
For a given Physician (e.g. id 2), I would like to get all their patients with an appointment AND their appointment date.
I can do a GET operation like this:
GET /physicians/2
with the filter header { "include" : {"relation":"patients"} }
And I do get the physician, and the list of patients, but I lose the appointmentDate of the relation.
Or, I can do a GET operation on the relation table like the documentation shows:
GET /appointments
with the filter header { "include" : {"relation":"patient"}, "where":{"physicianId":2}} }
And I get the the appointments, with the date and the patient embedded, but not the physician details.
I can't seem to be able to combine the two.
Is there a way to get the whole data with one query?
The data would be something like this:
[
"name" : "Dr John",
"appointments" : [ {
"appointmentDate": "2014-06-01",
"patient": {
"name": "Jane Smith",
"id": 1
}
}]
]
One way hack I found is to define the relation twice. Once as a HasManyThrough and once as a HasMany to the appointments table, then I can do something like this:
GET /physicians/2
with the filter header { "include" : {"relation":"appointments","scope":{"include":["patient"]} } }
But that doesn't seem right, or could maybe lead to odd behaviours with the duplicated relation.. but maybe I'm paranoid.
You could include both models
GET /appointments
{ "include": ["patient", "physician"], "where": { "physicianId":2 } }
You will get quite a lot of duplicate data though (details of physician with id 2). I believe, that HasManyThrough relation model was initially not supposed to carry any extra data and therefore, it has some limitations. Here is a related github issue.

How can I use scan/scroll with pagination and sort in ElasticSearch?

I have a ES DB storing history records from a process I run every day. Because I want to show only 20 records per page in the history (order by date), I was using pagination (size + from_) combined scroll, which worked just fine. But when I wanted to used sort in the query it didn't work. So I found that scroll with sort don't work. Looking for another alternative I tried the ES helper scan which works fine for scrolling and sorting the results, but with this solution pagination doesn't seem to work, which I don't understand why since the API says that scan sends all the parameters to the underlying search function. So my question is if there is any method to combine the three options.
Thanks,
Ruben
When using the elasticsearch.helpers.scan function, you need to pass preserve_order=True to enable sorting.
(Tested using elasticsearch==7.5.1)
yes, you can combine scroll with sort, but, when you can sort string, you will need change the mapping for it works fine, Documentation Here
In order to sort on a string field, that field should contain one term
only: the whole not_analyzed string. But of course we still need the
field to be analyzed in order to be able to query it as full text.
The naive approach to indexing the same string in two ways would be to
include two separate fields in the document: one that is analyzed for
searching, and one that is not_analyzed for sorting.
"tweet": {
"type": "string",
"analyzer": "english",
"fields": {
"raw": {
"type": "string",
"index": "not_analyzed"
}
}
}
The main tweet field is just the same as before: an analyzed full-text field.
The new tweet.raw subfield is not_analyzed.
Now, or at least as soon as we have reindexed our data, we can use the
tweet field for search and the tweet.raw field for sorting:
GET /_search
{
"query": {
"match": {
"tweet": "elasticsearch"
}
},
"sort": "tweet.raw"
}

Ember Data Nested Resources Tree Structure

I have a slightly peculiar problem with loading my tree structure into Ember.
My models are:
book.js
- parts: DS.hasMany('part', {inverse: 'book', async: true})
part.js
- subparts: DS.hasMany('part', {inverse: 'parent_part', async: true}),
With the following API responses:
GET /api/books:
{
books: [
{id: 1, links: {parts: "/api/books/1/parts"}},
...
]
}
GET /api/books/1/parts:
{
parts: [
{
id: 1,
subparts: [10, 11]
},
{
id: 2,
subparts: []
}
]
}
The problem is in the tree nature of the parts: The book only has direct descendants id 1 and 2, but these have sub-parts on their own.
The structure as it is works but results in multiple sub-queries for each part that was not included in the /books/1/parts result. I want to avoid these queries, not only because of performance reasons but also because I will need additional query parameters which would get lost at this step... I know about coalesceFindRequests but it introduces new problems.
To rephrase the problem, Ember Data thinks that every part that is included in the /books/1/parts response should be added directly to the book:parts property. How can I still load all records of the parts tree at the same time?
I tried renaming the fields, but Ember Data assigns the records based on the model name, not the field name.
I fear that some creative adapter overriding will be necessary here. Any idea appreciated. The backend is completely under my control, so I could change things on that end, too.
You need to use a process called sideloading, which should work as you expect (I've had issues in the past with sideloading data). As mentioned in this issue, you want to split your parts into two separate arrays.
{
// These are the direct children
"parts": [{...}, {...}],
// These are the extra records
"_parts": [{...}, {...}]
}

Loopback Filter Based On Related Model Properties

I want to be able to filter based on the properties of related models. For example, I have a Class object with a Building object. I want to get a list of classes that take place in a certain building.
This filter
{
"include":"building",
"scope":{
"where":{
"name":"warehouse"
}
}
}
returns all classes, but only includes building if its name is "warehouse". What I want is for the where clause on building name to apply to the whole filter so that I only get the class if it's building has that name.
Is there any way to do what I want?
Thanks!
You can do this in code, see include with filters in the docs.
I'm not sure about the JSON but I think it should look more like this:
"include": {
"relation": "building",
"scope": {
"where": {"name": "warehouse"}
}
}
At the moment this is not possible. The issue has been described in this topic; https://github.com/strongloop/loopback/issues/517
It looks like Strongloop is not going to implement this feature in the near future.
Whenever you want to use it on API CALL , you can follow a model like this one
and adapt it to your context.
//Here (as filter) , we get just the most recent message of a chat
{
"include" : {
"relation" : "messages" ,
"scope" :
{
"order" : "createdAt DESC" ,
"limit":1,
"skip":0
}
}
}
At the moment this is not possible in loopback, but you can use this component for resolve this ploblem. It is an easy to use and works perfectly.
https://www.npmjs.com/package/loopback-component-relation-filter
after you configure the component in the component-config.json file as the component documentation says. You can resolve your problem with.
assuming that the main model is called classes and that it has the relationship called building.
var filter = {
where: {
building:{ name:"warehouse" }
}
}
app.models.classes.find(filter, console.log);
That code only returns the classes when building name is warehouse.