how to get specific field in an included object - loopbackjs

I'm trying to get a specific field in a api call from an included object.
I get an empty array.
filter =
{"where":{"type":"person"}, "include":["objectA"], "fields":"objectA.name"}
What am i doing wrong?

If for example you have the following data model:
Model: Customer.
Fields: id, name.
Model: Order.
Fields: id, date, description, customerId.
Order.belongsTo(Customer, {foreignKey: ‘customerId’});
You can get only the Customer name by writing this filter:
var filter = {
"where": {
"id": 1
},
"include": [
{
"relation": "customer",
"scope": {
"fields": [
"name"
]
}
}
]
}
Order.find(filter, function(err, order) {
...
})
and in your case i'm guessing the filter suppose to be something like this:
{
"where": {
"type": "person"
},
"include": {
"relation": "objectA",
"scope": {
"fields": ["objectA.name"]
}
}
}

Related

Problems Using #queryField For Sorted Lists with AWS Amplify

This is a follow-up to a previous question I had (Elements Pulled From AWS Not Being Sorted Properly).
After following the advice given, I generated code for a query listSortedAlbumCategories seen here:
export const listSortedAlbumCategories = /* GraphQL */ `
query ListSortedAlbumCategories(
$id: ID
$sortOrder: ModelIntKeyConditionInput
$sortDirection: ModelSortDirection
$filter: ModelAlbumCategoryFilterInput
$limit: Int
$nextToken: String
) {
listSortedAlbumCategories(
id: $id
sortOrder: $sortOrder
sortDirection: $sortDirection
filter: $filter
limit: $limit
nextToken: $nextToken
) {
items {
id
title
sortOrder
albums {
nextToken
}
createdAt
updatedAt
}
nextToken
}
}
Then, I updated my code to use that query:
useEffect( () => {
const fetchAlbumCategories = async() => {
try {
const data = await API.graphql(graphqlOperation(listSortedAlbumCategories));
setCategories(data.data.listSortedAlbumCategories.items);
} catch (e) {
console.log(e);
}
}
console.log("Fetching album categories...")
fetchAlbumCategories();
},[]);
However, I get the following error message:
Object {
"data": null,
"errors": Array [
Object {
"locations": Array [
Object {
"column": 15,
"line": 1,
"sourceName": null,
},
],
"message": "Variable 'id' has coerced Null value for NonNull type 'ID!'",
"path": null,
},
],
}
Object {
"data": Object {
"listSortedAlbumCategories": null,
},
"errors": Array [
Object {
"data": null,
"errorInfo": null,
"errorType": "MappingTemplate",
"locations": Array [
Object {
"column": 3,
"line": 2,
"sourceName": null,
},
],
"message": "Expression block '$[query]' requires an expression",
"path": Array [
"listSortedAlbumCategories",
],
},
],
}
I can't seem to find the issue with my query, it looks very similar to the original listAlbumCategorys but with the sortOrder added. Please help!
Queries on a table or GSI require that you specify the partition key. You cannot get a sorted response from DynamoDB without specifying a partition key.
The GSI you have configured requires you to specify “id”.
You can get around this in your case by setting the partition key to a constant value for all items, like “category”.

How to nested include through models relationships LOOPBACK?

Lets continue with the Patient - Physician analogy from the Loopback Docs. Let's make the assumption that Physician model looks like this:
{
"id": "4654654654654654654",
"name": "John Doe"
}
and Patient model looks basiclally the same (only id and name) and two models are connected with HasManyThrough relationship with through model called Appointment as in the docs. https://loopback.io/doc/en/lb2/HasManyThrough-relations.html
My question is, when you GET to /api/physicians url how can you query the response so it includes the appointment date as well as patient for every physician?
Wanted output:
{
"id": "4654654654654654654",
"name": "John Doe",
"patients": [
{ "id": "1321232313", "name": "First Patient", "appointment_date": 1995-12-17T03:24:00 },
{ "id": "1321232313", "name": "Second Patient", "appointment_date": 1995-12-17T03:24:00 }
]
}
Field "appointment_date" is the date from the appointment through model and patient names are obtained through nested including of same model.
Any thoughts?
Use Nested Include Just check link Its help.
Please check this Code :
physicians.find(
{
include: {
"relation": "Appointment",
"scope": {
"fields": ["id", "patientId", "AppointmentDate", "physiciansId"], /*need to include both Person and PersonID fields for this to work*/
"include": {
"relation": "patient",
"scope": {
"fields": {"id": true, "patienName": true},
where: {id: patientId},
}
}
}
}
}

Loopback include filter within scope works for GET but fails for POST request

I have this scope defined in my order.json which has relation with branch and customer along with other properties.
"name": "Order",
"properties":{...},
"relations": {...},
"acls": {...},
"scope": {
"include": [
{"relation": "branch", "scope": { "fields": "BranchName" } },
{"relation": "customer", "scope": { "fields": "CustomerName" } }
]
}
This works well as expected in all GET requests with following results
[
{
"OrderDate": "2018-01-12T17:52:21.000Z",
"CustomerId": 39,
"BranchId": 5,
"CustomerRef": "Order by Phone",
...
"CreatedBy": 1,
"id": 1,
"branch": {
"BranchName": "aaaa",
"id": 5
},
"customer": {
"CustomerName": "xxxx",
"id": 39
}
}
]
I was expecting a similar result, however, the response array received after a successful POST request does not include BranchName and CustomerName info from the related models.
Am I doing it correctly? or is there any other way to get back information from related models after a Create/Update operation. I am just trying to avoid another GET request immediately after Create/Update.
You can use the Operation hook after save.
Order.observe('after save', function(ctx, next) {
if (ctx.instance) {
ctx.instance.relatedmodel = someFunctionToGetRelatedModel();
}
next();
});
Whatever is inside the ctx.instance should be included in loopbacks responses.
You just have to figure out how to seamlessly pull the related model details, you want to include.

Why is this nested relation in LoopBack returning duplicate results?

When I query to include a nested model – e.g. GET /api/Widgets/1?filter={include: {"foos": "bars"}} – I get duplicate foos in my results. I thought this was due to a LEFT JOIN or something like that, as I'm using MySQL, but when I run LoopBack in the loopback:connector:mysql debug mode, I can see that the query for the initial widget runs once, but that the query for foo runs twice, and the query for bar runs twice. Why is this behavior occurring, and what can I alter (my models, my code or my expectations)?
Models:
{
"name": "Widget",
...
"relations": {
"foos": {
"type": "hasMany",
"model": "Foo",
"foreignKey": "widgetId"
}
}
}
{
"name": "Foo",
...
"relations": {
"bars": {
"type": "hasMany",
"model": "Bar",
"foreignKey": "fooId"
},
"widget": {
"type": "belongsTo",
"model": "Widget",
"foreignKey": ""
}
}
}
{
"name": "Bar"
...
"relations": {
"foo": {
"type": "belongsTo",
"model": "Foo",
"foreignKey": ""
}
}
}
Results:
{
id: 1
foos: [
{
id: 2,
bars: [
{
id: 3
}
]
},
{
id: 2,
bars: [
{
id: 3
}
]
}
]
}
Expecting:
{
id: 1
foos: [
{
id: 2,
bars: [
{
id: 3
}
]
}
]
}
This is paraphrased SQL that I see being run for this request:
SELECT `...` FROM `Widget` WHERE `id`=1 ORDER BY `id` LIMIT 1
SELECT `...` FROM `Foo` WHERE `widget_id` IN (1) ORDER BY `id`
SELECT `...` FROM `Foo` WHERE `widget_id` IN (1) ORDER BY `id`
SELECT `...` FROM `Bar` WHERE `foo_id` IN (2) ORDER BY `id`
SELECT `...` FROM `Bar` WHERE `foo_id` IN (2) ORDER BY `id`
I'm using Loopback 3.x.
Update: While a request of GET /api/Widgets/1?filter={include: {"foos": "bars"}} exhibits this behavior, a server-side execution of Widgets.findById(id, {include: {"foos": "bars"}}) works perfectly. So, at the moment I'll create a remote method that does this and perhaps file a bug report with LoopBack.
I was using this mixin that limits the limit of a query to max out at a defined value. When include is present in a query, the mixin also sets a limit on the scope of the include like so:
"include": {"foo":"bar","scope":{"limit":1}}
Seems the mixin was assuming all includes that are objects would be written in the form of {"relation":"foo", "scope":{"include:"bars"}}, so includes were getting added twice.
For what it's worth, I wrote this simple mixin to limit the maximum number of results unless specified and stopped using the one linked above:
common/models/model.json:
"mixins": {
"ResultsetLimit": {
"limit": 100
}
}
common/mixins/resultset-limit.js:
const _ = require('lodash');
module.exports = (Model, options) => {
/**
* Modify incoming query to apply appropriate limit filters.
*/
Model.beforeRemote('**', (ctx, unused, next) => {
// Get the limit from the request, defaulting to the max limit.
const request_limit = _.toNumber(_.get(ctx, 'args.filter.limit', options.limit));
// Set the limit.
_.set(ctx, 'args.filter.limit', request_limit);
next();
});
};
have you tried removing the following lines?
Because by default, if foreignKey is NOT set, it will set it as <relationName>Id. But since you set it to blank, loopback is not looking for any column to reference to. hence it is getting all the records on your related model.
{
"name": "Widget",
...
"relations": {
"foos": {
"type": "hasMany",
"model": "Foo",
"foreignKey": "widgetId"
}
}
}
{
"name": "Foo",
...
"relations": {
"bars": {
"type": "hasMany",
"model": "Bar",
"foreignKey": "fooId"
},
"widget": {
"type": "belongsTo",
"model": "Widget",
"foreignKey": "" // remove this
}
}
}
{
"name": "Bar"
...
"relations": {
"foo": {
"type": "belongsTo",
"model": "Foo",
"foreignKey": "" //remove this
}
}
}
UPDATE:
This is how I call 2nd (or 3rd) level relations:
/api/Widgets/1?filter={include: [{"relation":"foo", "scope":{"include:"bars"}}]}

How to include nested relationships?

At http://jsonapi.org/format/#fetching-includes
Articles belongs to an author. Articles have many comments. Comments belongs to a user.
Trying to understand how to include nested relationships. Take for example: https://www.foo.com/articles?include=comments
You would expect:
{
data: [
{
id: 1,
type: "articles",
attributes: { ... },
relationships: {
author: { ... },
comments: [{ ... }, { ... }],
},
...
},
{ ... }
]
included: [
{
author: { ... },
comment: { ... },
comment: { ... }
{
]
}
Now lets say, you wanted to include the users who wrote those comments. https://www.foo.com/articles?include=comments.user
Should the response look like:
{
data: [
{
id: 1,
type: "articles",
attributes: { ... },
relationships: {
author: { ... },
comments: [{ ... }, { ... }]
},
...
},
{ ... }
]
included: [
{
author: { ... },
comment: { ... },
comment: { ... },
user: { ... },
user: { ... }
{
]
}
Should users (users who wrote the comments) also be in the relationship node, or just in the included node?
If in the relationship node. Should user be nested inside data.relationships.comments? How would that look?
According to the Top Level documentation, the included field should be an array of Resource Objects. This means your included field should look like this:
"included": [
{
"type": "author",
"id": ...,
"attributes": { ... },
"relationships": { ... }
}, {
"type": "comment",
"id": ...,
"attributes": { ... },
"relationships": { ... }
}
]
Also according to the Relationships documentation, it should (when side-loading data) contain a Resource Linkage data field which will contain either a single Resource Identifier in the case of a belongsTo relationship, or an array of resource identifier objects in the case of a hasMany relationship.
belongsTo resource identifier:
"relationships": {
"author": {
"links": { ... },
"data": { "type": ..., "id": ... }
},
"comments": {
"links": { ... },
"data": [
{ "type": ..., "id": ... },
{ "type": ..., "id": ... }
]
}
}