How to create register with relation model embeded? - loopbackjs

I'm using Loopback 3 to create my application, with Postgres.
I've created a many-to-many usign hasManyThrough relation like this:
Product has many Composition
Ingredient has many Composition
Product has many Ingredient
Composition belongs to Product
Composition belongs to Ingredient
How can I create/edit a Product with a array of Ingredient's id, like:
POST /products
{
name: "Potato Chips",
ingredients: [ 5, 7, 3, 20 ]
}
And how can I get Product with list of Ingredients embeded?
GET /products/1
{
id: 1,
name: "Potato Chpis",
ingredients: [
{ name: "Potato" },
{ name: "Vegetal Oil" }
...
]
}

1/ To create a Product with many Ingredients, I suggest to make a custom remote that takes your product in the body along with the ingredients, and make a loop over the ingredients to link them to your product one by one, using the add method (assuming that Product has many Ingredients through Composition):
Product.ingredients.add(ingredientData, callback);
2/ To get a Product with its embedded list of Ingredients, you need to include the relation property to your GET route (example given in reactjs):
const response = await Axios.get(`/api/products/${productId}`, {
params: {
filter: {
include: [
{ relation: 'ingredients' },
],
},
},
});

Related

TypeORM: How to set ForeignKey explicitly without having property for loading relations?

I don't want to create a property for loading relation into it (as shown in all the examples). The only thing I need is to have an explicit foreign key property so that the migration will be able to create appropriate constraints for it in the database. The closest decorator to the one I need is #RelationId but it still requires the presence of a property of the relational class.
For clarity let's take the example from the documentation:
#Entity()
export class Post {
#ManyToOne(type => Category)
category: Category;
#RelationId((post: Post) => post.category) // it still requires the presence of the `category` proeprty
categoryId: number;
}
I don't need the category property here. I want to have the categoryId property and mark it as foreign key to Category.Id. It should look like this:
#Entity()
export class Post {
#ForeignKey((category: Category) => category.Id) // it's a foreign key to Category.Id
categoryId: number;
}
Is it possible?
"I need is to have an explicit foreign key property"...
No, you could not. TypeOrm will automatically create foreign key property when you use #ManyToOne decorator. Just combine #ManyToOne and #JoinColumn decorators together like this:
#ManyToOne(type => Category)
#JoinColumn({ name: 'custom_field_name_if_you_want' })
category: Category;
Maybe you can create and write your own migration and use it like this :
const queryRunner = connection.createQueryRunner();
await queryRunner.createTable(new Table({
name: "question",
columns: [
{
name: "id",
type: "int",
isPrimary: true
},
{
name: "name",
type: "varchar",
}
]
}), true);
await queryRunner.createTable(new Table({
name: "answer",
columns: [
{
name: "id",
type: "int",
isPrimary: true
},
{
name: "name",
type: "varchar",
},
{
name: "questionId",
isUnique: connection.driver instanceof CockroachDriver, // CockroachDB requires UNIQUE constraints on referenced columns
type: "int",
}
]
}), true);
// clear sqls in memory to avoid removing tables when down queries executed.
queryRunner.clearSqlMemory();
const foreignKey = new TableForeignKey({
columnNames: ["questionId"],
referencedColumnNames: ["id"],
referencedTableName: "question",
onDelete: "CASCADE"
});
await queryRunner.createForeignKey("answer", foreignKey);
This code snippet is extracted from the functional test of type orm and you can use it to create your own constraint on the database I think.
It's actually possible to do so:
#Entity()
export class Post {
// this will add categoryId
#ManyToOne(type => Category)
category: Category;
// and you can use this for accessing post.categoryId
// only column you mark with #Column decorator will be mapped to a database column
// Ref: https://typeorm.io/#/entities
categoryId: number;
}
The added categoryId won't be mapped to column and will then be use for setting explicitly the id or for accessing its value as in:
post.categoryId = 1;
// or
const id = post.categoryId
Check with these two places Auth module(JwtModule.register()) and JWT strategy(super({...})). Make sure you have secret /secretOrKey is set to the same key. In my case "secret: process.env.JWT_SECRET_KEY" & "secretOrKey: process.env.JWT_SECRET_KEY"
I have encountered the same problem recently.
I still use the Entity but only with the primary key value of the referenced entity.
i.e. I do not query the database for the referenced entity.
Suppose your category entity looks like this:
#Entity()
export class Category{
#PrimaryGeneratedColumn()
id: number;
// ... other stuff
}
Now using your codes as example.
Dircely assigning relation using a foreign key value would be like.
// You wish to assign category #12 to a certain post
post.category = { id: 12 } as Category

Creating model with nested objects and arrays in Loopback version LB4

I've just started with Loopback for the first time and I've started with LB4, their newest release. I'm looking to create a model with nested objects and arrays as per my JSON schema to which I followed the documentation which allowed me to create the base values of my schema, but I need to create the fields inside the objects and arrays, but I can't find the documentation or articles to help me understand this...
This is my JSON schema I'm trying to create a LB4 model with:
"socialProfiles": {
"facebook": {
"linked": 1,
"pullData": 1,
"linkID": 4434343,
"profile": "https://www.facebook.com/FBURL",
"registered": {
"date": "2018-05-04T12:41:27.838Z",
"verified": "2018-05-04T12:41:27.838Z",
"by": {
"id": 1,
"user": "USER"
}
}
},
}
Using the LB4 documentation, I can create my main field socialProfiles but I can't find where I go to create my fields inside this object... Here's my LB4 model code
import {Entity, model, property} from '#loopback/repository';
#model()
export class Users extends Entity {
#property({
type: 'object',
})
socialProfiles?: object;
constructor(data?: Partial<Users>) {
super(data)
}
}
How to do this?
If you want to store the object in the model itself (not with a relation), you can create an interface with something like:
export interface ISocialProfile {
"linked": number,
"pullData": number,
"linkID": number,
"profile": string,
"registered": {
"date": Timestamp,
"verified": Timestamp,
"by": {
"id": number,
"user": string
}
}
}
and then in your model, you can just add the type:
socialProfiles?: {[name: string]: ISocialProfile};

EmberJS - Multiple hasMany relationship on same attribute

I have below json and I want to add multiple has many relationship.
{
"Id": "2311",
"package": [
{
"0": "233123"
},
{
"1": "1987797"
}
]
}
I want something like this in my model.
package : hasMany('package'),
package : hasMany('name'),
How can I use the hasMany relationship on same attribute for 2 models ?
I'm not sure I understand your question.
When you define hasMany relationship, for example, a client hasMany packages, you get the following representation in your database:
Client 1 { // Client model hasMany relationship to Package model
name: "client1"
id: "1234"
}
Package 1 {
name: "package1"
id: "233123"
client: "1234" // this package belongs to client 1
}
Package 2 {
name: "package2"
id: "1987797"
client: "1234" // this package also belongs to client 1
}
Are you saying you want your Client model to hold 2 hasMany relationships, one for the Package name and one for the Package ID?
Please provide a bit more detail and I'll help you answer the question.

Multi-level include filter with LoopBack JS

My problem is that I can't figure out how to get multilevel relations structures in one request with LoopBack backend. I have 3 models: Continent, Country, County. What I would like to do is to GET a continent, and recieve all the countries, and all the counties within.
The relationship between them:
Continent hasMany Country, and Country belongsTo Continent
Country hasMany County, and County belongsTo Country
So the REST api call to /api/Continent/1 returns
{
"id": 1
"name":"Europe"
}
Now, I want to get all the countries and counties with the Continent, so I do a query to /api/Continent/1?filters[include]=country
Still, I don't get the countys.
What kind of query should I make to get a list which includes both relation levels? Like this:
{
"id": 1,
"name": "Europe",
"country": [
id: 1,
name:"United Kingdom",
county:[
{id:1,name:"Avon"},
{id:2,name:"Bedfordshire"},
...
],
...
]
}
Thanks for your help!
The syntax is:
/api/Continent/1?filter={"include": {"country": "countys"}}
Hello hoping it's not too late for an answer. After a thorough flipping of their docs inside and out on this issue, I ended up writing a remote method to achieve that deep level multiple includes. It's not so clear how to go about it at the REST api level.
Continent.listContinents = function(limit,skip,order,cb) {
Continent.find({
limit:limit,
skip:skip,
order:order,
include:[{country:'county'}],
}, cb);
};
Continent.remoteMethod('listContinents', {
description:"List continents. Include the related country and county information",
returns: {arg: 'continents', type: 'array'},
accepts: [{arg: 'limit', type: 'number', http: { source: 'query' }},
{arg: 'skip', type: 'number', http: { source: 'query' }},
{arg: 'order', type: 'string', http: { source: 'query' }}],
http: {path:'/list', verb: 'get'}
});
I have added some additional query string parameters limit, order and skip to enable pagnination and ordering..but not a must :)
Also this is assuming you already have relation types defined between Continent and Country then Country and County.

Updating multiple objects with ember-data and non-rest action

Lets say I have a Customer who hasMany products
The api has a PUT: /customers/:id/cancel that cancels the customer and also cancels all the products and then returns the customer and the products for sideloading:
{
customer: {
id: 1,
name: "Customer Name",
canceled: true,
products: [1, 2] },
products: [
{id: 1, customer_id: 1, name: "Product 1", canceled: true},
{id: 2, customer_id: 1, name: "Product 2", canceled: true}
]
}
how would I:
Call that action on the customer?
Update all objects in the Ember Store?
For part 1. of your question,
You'll want to find it in the store var customer = store.find('customer', 1);
Then tell it to delete customer.destroyRecord();
And finally commit the delete customer.save();
For part 2. deleting the products, you'll have to do delete them manually in a forEach loop, tucked inside an Ember.run.once., as there is no cascading delete in ember data at this stage of the game.
Here is an example of this for a top level delete, so you would need to follow the same logic but for your products and follow it up with a .then that deletes your connected customer.
Single tier Example: http://jsbin.com/samegiqe/1/edit?js,output
Connected StackOverflow for further reading: How to delete all records associated with an ember model without clearing local Storage?
Complex mixin to solve this: http://jsbin.com/hupabovo/1/edit
Its connected StackOverflow: Delete associated model with ember-data
Hope that gets at what you were asking. Cheers!