How are composite ids working in Loopback? - mongodb

I am trying to implement composite ids with Loopback 3.0.0 using MongoDB. each pair of product_id/keyword should be unique...
I check the official documentation:
https://loopback.io/doc/en/lb3/Model-definition-JSON-file.html#data-mapping-properties
Here my model:
{
"name": "comparative",
"plural": "comparative",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"product_id": {
"id": true,
"type": "string",
"required": true
},
"keyword": {
"id": true,
"type": "string",
"required": true
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": {}
}
Although, all my attempts to make composite ids of product_id/keyword failed.
When I POST:
// 1st POST Success.
{
"product_id": "string",
"keyword": "string"
}
// 2nd POST Success.
{
"product_id": "string1",
"keyword": "string"
}
// 3rd POST FAILED -> I want it to success
{
"product_id": "string",
"keyword": "string1"
}
Any ideas?
Even after that, I need to keep an auto-generated MongoDB id just to keep track of the objects.
I tried with "idInjection", not working along with composite ids... (not generating anything...)
If I add another field "id" with generated set to true, composite ids doesn't work at all (contrary as before where it worked partially)
Thank you,

You can declare a composite index between product_id and keyword:
https://loopback.io/doc/en/lb3/Model-definition-JSON-file.html#indexes
{
"name": "comparative",
"plural": "comparative",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"product_id": {
"type": "string",
"required": true
},
"keyword": {
"type": "string",
"required": true
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": {},
"indexes": {
"productid_keyword_index": {
"keys": {
"product_id": 1,
"keyword": -1
},
"options": {
"unique": true
}
}
}
}

You don't have to put id: true in the properties. This is done only to a single field, if you don't want the default identification ie. _id in mongo
"properties": {
"product_id": {
"type": "string",
"required": true
},
"keyword": {
"type": "string",
"required": true
}
}
I assume that you have another model Product to which you want relate this model. In order to achieve this, add relations
check this loopback documentation to do so.
Hope this helped

Related

LoopBack WARNING: id property cannot be changed from to

I'm using LoopBack with MongoDB as my datasource and have a simple model defined as:
{
"name": "restaurant",
"plural": "restaurants",
"base": "PersistedModel",
"idInjection": false,
"options": {
"validateUpsert": true
},
"properties": {
"name": {
"type": "string",
"required": true
},
"address": {
"type": "string",
"required": true
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": {}
}
I have an auto-migrate script in my /server/boot which creates two simple test data.
After that when I try to update one of those entries with PUT request using LoopBack's API explorer I get a warning
WARNING: id property cannot be changed from ... to ... for model:restaurant in 'before save' operation hook
WARNING: id property cannot be changed from ... to ... for model:restaurant in 'loaded' operation hook
and redundant id field (same as mongo's _id field) is created in DB.
I was able to prevent the creation of the redundant id field by setting idInjection to false and defining another property in model definition as:
"_id": {
"id": true,
"generated": true
}
However, I still get the warning after doing a PUT request from LoopBack's API explorer.
How should the mongo's _id field be defined in model definition properly?
Thanks.
You could hide the id by adding a "hidden" field to your model JSON. And add "id" to the array to be hidden.
{
"name": "restaurant",
"plural": "restaurants",
"hidden": [
"id"
],
"base": "PersistedModel",
"idInjection": false,
"options": {
"validateUpsert": true
},
"properties": {
"name": {
"type": "string",
"required": true
},
"address": {
"type": "string",
"required": true
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": {}
}

Loopback: Relation Through - not working

So, I am stuck on an issue, that should be simple, and I am sure I am missing something obvious
I am following this documentation:
so I have 3 tables
client, team, client-team
client.json
{
"name": "client",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"name": {
"type": "string",
"required": true
}
},
"validations": [],
"relations": {
"teams": {
"type": "hasMany",
"model": "team",
"foreignKey": "teamId",
"through": "client-team"
}
},
"acls": [],
"methods": {}
}
team.json
{
"name": "team",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"type": {
"type": "string",
"required": true,
"default": "first-team"
},
"name": {
"type": "string",
"required": true
}
},
"validations": [],
"relations": {
"clients": {
"type": "hasMany",
"model": "client",
"foreignKey": "clientId",
"through": "client-team"
}
},
"acls": [],
"methods": {}
}
client-team.json
{
"name": "client-team",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"clientId": {
"type": "string",
"required": true
},
"teamId": {
"type": "string",
"required": true
}
},
"validations": [],
"relations": {
"client": {
"type": "belongsTo",
"model": "Client",
"foreignKey": "clientId"
},
"team": {
"type": "belongsTo",
"model": "Team",
"foreignKey": "teamId"
}
},
"acls": [],
"methods": {}
}
so all the relations set correctly (I think)...
then in my clients I do have 1 client
[
{
"name": "Client name",
"id": "59876185508eb519385779c6"
}
]
and in my teams I have many, but for sure this:
[
{
"type": "type",
"name": "Team name",
"id": "5ae8a37add2989a32d37f83d"
}
]
And then I go to my
localhost:3000/explorer
To POST a client-team
like this
{
"clientId": "59876185508eb519385779c6",
"teamId": "5ae8a37add2989a32d37f83d"
}
and I get the 200 response with:
{
"clientId": "59876185508eb519385779c6",
"teamId": "5ae8a37add2989a32d37f83d",
"id": "5ae961873a7e3b33f0579fc3"
}
so the connection is there....
But then, when I go to "GET client/id" and do
id: 59876185508eb519385779c6
filter: {"include":["teams"]}
this is the response
{
"name": "Chelsea FC",
"id": "59876185508eb519385779c6",
"teams": []
}
The same happens in the "GET teams/id" and I use
id: 5ae8a37add2989a32d37f83d
filter: {"include":["clients"]}
or if I go to "GET teams/{id}/clients"
and put
id: 5ae8a37add2989a32d37f83d
I get
[]
So what am I doing wrong? I am sure I am missing a stupid, obvious thing :/
using mongo if that makes any difference
There are three issues here:
You described mongodb identifiers as string, that's why you store strings in database instead of object ids. (it's not required as the datasource should understand the real type)
Your models start from lower case letter. The same should be in the relations also. (the first part of the problem, it's fixing issue with ids)
Incorrect relations for client and team models (the second part of the problem, it's fixing includes)
client-team.json
{
"name": "client-team",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"clientId": {
"type": "objectId", // !!! changed (not required)
"required": true
},
"teamId": {
"type": "objectId", // !!! changed (not required)
"required": true
}
},
"validations": [],
"relations": {
"client": {
"type": "belongsTo",
"model": "client", // !!! changed
"foreignKey": "clientId"
},
"team": {
"type": "belongsTo",
"model": "team", // !!! changed
"foreignKey": "teamId"
}
},
"acls": [],
"methods": {}
}
client.json
{
"name": "client",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"name": {
"type": "string",
"required": true
}
},
"validations": [],
"relations": {
"teams": {
"type": "hasMany",
"model": "team",
"foreignKey": "clientId", // !!! changed (we describing id of this model, not team)
"through": "client-team"
}
},
"acls": [],
"methods": {}
}
team.json
{
"name": "team",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"type": {
"type": "string",
"required": true,
"default": "first-team"
},
"name": {
"type": "string",
"required": true
}
},
"validations": [],
"relations": {
"clients": {
"type": "hasMany",
"model": "client",
"foreignKey": "teamId", // !!! changed (the same as the previous)
"through": "client-team"
}
},
"acls": [],
"methods": {}
}

LoopBack 3.0: where filter not returning results from REST API

I have a LoopBack API with a single simple model like this:
{
"name": "Establishment",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"Distance": {
"type": "number"
},
"EstablishmentId": {
"type": "number"
},
"EstablishmentType": {
"type": "string"
},
"Location": {
"type": "string"
},
"MinCost": {
"type": "number"
},
"Name": {
"type": "string"
},
"Stars": {
"type": "number"
},
"UserRating": {
"type": "number"
},
"UserRatingTitle": {
"type": "string"
},
"UserRatingCount": {
"type": "number"
},
"ImageUrl": {
"type": "string"
},
"ThumbnailUrl": {
"type": "string"
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": {}
}
A simple call to http://localhost:3000/api/Establishments returns all of the results, as expected; but a call to http://localhost:3000/api/Establishments?filter[where][distance][gt]=30 yields no results at all: an empty array.
There are lots of Establishments with a Distance greater than 30; and indeed using the where filter on other properties also results in an empty array. What could I be missing?
As I mentioned in the comment, it is case-sensitive and I varified it on my app to be certain about it.
it should be :
http://localhost:3000/api/Establishments?filter[where][Distance][gt]=30
or you can try with this format :
http://localhost:3000/api/Establishments?filter={"where":{"Distance":{"gt":30}}}

How to create a reference in loopback?

I'm new with loopback and I have some issues with relations.
I have these two models:
course
{
"name": "course",
"plural": "courses",
"base": "PersistedModel",
"idInjection": false,
"options": {
"validateUpsert": true
},
"properties": {
"name": {
"type": "string",
"required": true
}
},
"validations": [],
"relations": {
"toughtBy":{
"type": "embedsMany",
"model": "teacher",
"foreignKey":"",
"options": {
"validate": true,
"forceId": false
}
},
"acls": [],
"methods": {}
}
teacher
{
"name": "teacher",
"plural": "teachers",
"base": "PersistedModel",
"idInjection": false,
"options": {
"validateUpsert": true
},
"properties": {
"name": {
"type": "string",
"required": true
},
"lastName": {
"type": "string",
"required": true
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": []
}
How can I add a existing teacher in an existing course ?
I tried a use the API put /courses/{id}/toughtBy/{fk}, but I get an empty body.
To confirm but I believe you did not create a course first prior to calling
POST api/courses/1/thoughtBy/1, thus you are trying to update a related model instance from a model instance that doesn't exists.
By the way, rather than using course embedsMany teacher, I would recommend you use the following patter:
course hasAndBelongsToMany teacher
then use
POST api/courses/ to create a course
POST api/teachers to create a teacher
POST api/courses/link/ with teacherid=1 and courseid=1 to link the both

How do I change the schema of a postgres data source in strongloop?

I'm trying to tell strongloop that my gallery table has moved to the products schema. Adding it to the model definition in common/models/gallery.json seemingly has no effect. New to strongloop. What am I doing wrong?
My current schema. "schema": "products" is the only thing added.
{
"name": "gallery",
"plural": "galleries",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true,
"schema": "products"
},
"properties": {
"id": {
"type": "number"
},
"name": {
"type": "string",
"required": true
},
"description": {
"type": "string"
},
"uuid": {
"type": "uuid"
},
"test": {
"type": "string"
},
"order": {
"type": "number"
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": {}
}
uuid is a placeholder
Answer is here: https://docs.strongloop.com/display/public/LB/PostgreSQL+connector
Correct options value:
"options": {
"validateUpsert": true,
"postgresql": {
"schema": "products"
}
}