Connect LoopBack app to existing MySQL database - loopbackjs

I have a local MySQL database mydb. It contains a table called person, with fields id (primary key, integer auto-increment) and name (text). The table contains records that I do not want to delete.
I want a LoopBack app that connects to mydb through a data source myds. The app should have a model Person (which extends PersistedModel). CRUD operations on the Person model should be reflected on the people table of mydb.
How do I build the app?

Generate an empty application with the application generator.
>lb
? What's the name of your application? myapp
? Enter name of the directory to contain the project: myapp
? Which version of LoopBack would you like to use? 3.x (current)
? What kind of application do you have in mind? empty-server
Add a new datasource:
/* /server/datasources.json */
"myds": {
"host": "localhost",
"port": 3306,
"url": "",
"database": "mydb",
"password": "password",
"name": "myds",
"user": "root",
"connector": "mysql"
}
Install loopback-connector-mysql:
> npm install loopback-connector-mysql --save
Create a model
/* /common/models/Person.json */
{
"name": "Person",
"plural": "People",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"id": {
"type": "number",
"required": true
},
"name": {
"type": "string"
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": {}
}
Then attach the model to the data source.
/* /server/model-config.json */
{
// ...
"Person": {
"dataSource": "myds",
"public": true
}
//...
}
The app is complete. To run the app,
> node .
Then navigate to localhost:3000/explorer in a browser. Click on the Person model, then click on the route GET /People, then click "try it out!" The app should return all rows in the person table from the database. The other CRUD operations should also function properly.
Note that the naming is very important. When we connect a model named Person and to the datasource myds, which itself connects to the database mydb, LoopBack looks for a table called Person in mydb (this may interact with case-sensitivty of table names in your MySQL installation), with exactly the properties of Person as its field names.

Related

Loopback 3 Queries not returning expected results for MySQL data field

I have a content model that looks like:
{
"name": "content",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"id": {
"type": "number"
},
"url": {
"type": "string",
"required": false
},
"data": {
"type": "Object",
"required": true
}
},
"validations": [],
"relations": {},
"acls": [
{
"accessType": "WRITE",
"principalType": "ROLE",
"principalId": "$authenticated",
"permission": "ALLOW"
},
{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}
],
"methods": {}
Example of this data in MySQL looks like this:
I've tried querying this data both with REST and the Node API and haven't been able to query by any of the nested object fields inside of the "data" database field. A few examples that don't work:
contentModel.findOne({ where: { "data.url": url } }, function (
err,
content
) {
if (err) {
console.log(err);
}
console.log("find:", content);
});
const filter = encodeURI(`{"where":{"systemid":"${contentType}"}}`);
let url = `${apiUrl}contentTypes?filter=${filter}`;
let contentTypeRecord = await this.getAxios().get(url);
I've also tried many queries in the loopback swagger ui. I usually get no results or it returns all the content records.
The above data access attempts do however work if I have the same data setup in MongoDb.
What am I doing wrong? Loopback should presumably be parsing the object in the data field and allowing me to filter on it.
AFAIK, LoopBack does not support query filters on nested properties. According to this comment, there is a limited support in PostgreSQL and MongoDB connectors:
#michelgokan as you'll see from the thread:
There is some support in postgres connector
Mongo also has some basic support (only for dot nested properties)
Further support isn't going to be added to other RDB connectors as loopback 3 is in LTS and no longer accepting new feature PRs
Loopback 3 ends LTS at the end of 2019 so it's even less likely to be added.
Options are:
Write the custom SQL yourself as a custom endpoint
Create an alternate connector for something like Knex or Bookshelf that has support (big job)
Do the filtering in memory
Use json for the nested data to use dot queries in something like mongo or postgres
Look at migrating to loopback next which may add support in the future
It seems that MySQL supports querying of JSON data, see docs for JSON_CONTAINS, thus it should be possible to implement this feature in loopback-connector-mysql. Feel free to open an issue in https://github.com/strongloop/loopback-connector-mysql/issues. A pull request would be even better! ❤️

I am using loopback 3 and idInjection false is not working

My database is in PostgreSQL.My model defination is as below -
{
"name": "City",
"base": "PersistedModel",
"idInjection": false,
"options": {
"validateUpsert": true
},
"properties": {
"name": {
"type": "string"
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": {}
}
I am using code below to auto update the tables but when I go to database after running the code below and I check fields, I see id field created with an auto increment. How can I prevent creation of "id" field ?
ds.autoupdate("City", function (er) {
if (er) throw err
});
How can I prevent creation of "id" field?
If you're using a database, you can't. See this issue.
A model without any id properties can only be used without attaching to a database.
Making the name property an Id looks like the only way to use it with a relational database.
"name": {
"type": "string",
"id": 1
}

Loopback: Unknown column 'realm' in 'field list'"

I have been stuck with LoopBack for the last couple of hours trying to extend the User model with a custom model called Client.
{
"name": "Client",
"base": "User",
"plural": "Clients",
"idInjection": true,
"options": {
"validateUpsert": true,
"mysql": {
"schema": "LOOPBACK",
"table": "my_table_name"
}
},
"properties": {
"test": {
"type": "string"
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": {}
}
After doing the autoupdate I am not seeing any other properties in the client table than "test".
From the explorer I try to submit a new user, but I get the following error:
"uniqueness.Error: ER_BAD_FIELD_ERROR: Unknown column 'realm' in 'field list'"
Read every possible answer on google, but couldn't find a solution.
Try to manually create a column called 'realm' on your table 'my_table_name' and check if it fixes.
You need to exclude properties present in User but absent in your Model. My extended user has this property right before "properties" property:
"excludeBaseProperties": [
"realm",
"password",
"emailVerified",
"verificationToken"
],

loopback 2 - defining an array of objects on a model

if I have a usermodel and I define:
"events": {
"type": [
"Object"
]
},
Do I need to define anything else in the usermodel.js to be able to post things like: [{name: 'sample', ...}, ...] to the user table's events column?
I ask because if I remove this particular definition from the .json the app compiles and the database migrates, but with it in, the app compiles but the database states there was an issue with the users findByid. My debugging has narrowed it down to this particular set of code.
I think you can simply use this structure
{
"events":{
"type": [
{
"key": "type",
"key2": "type"
}
]
}
}
You can see a .js example here and .json example here.
but I can also see an issue with the implementation here that says
this model has problem. When we fetch the data with any get call, it
renders this particular field as ["Object Object"] even though the
data is properly saved in the database.
which I would recommend you to try on your own as it will depend a lot on versions and drivers.
Though I would like to ask that what kind of database are you using?
Another way would be to define the object you want in the array as a model, then use that model as your type:
Model: Class
{
"name": "Class",
"base": "Model",
"strict": true,
"idInjection": false,
"properties": {
"label": {
"type": "string",
"required": true
}
}
}
Model: Student
{
"name": "Student",
"base": "PersistedModel",
"strict": true,
"idInjection": true,
"properties": {
"classes": {
"type": ["Class"],
"required": false
},
}
}

How to query using numeric id in Loopback

I have a loopback model as
{
"name": "myModel",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"name": {
"type": "string",
"description": "Channel name"
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": {}
}
Now this is connected to a mongodb collection.This collection can have custom id in numeric like 1234 or Mongodb ObjectId when created using loopback.
Now when I query using GET
http://localhost:3000/api/myModel/1234.It is not able to get the object of that id.
I get an error message as
{"status":404,"statusCode":404,"code":"MODEL_NOT_FOUND","message": "Unknown \"myModel\" id \"1234\"}
If my id is alphanumeric like abcd1234 then I dont get this error.Is there a way in loopback to be able to process a numeric id.
The only reference I have is this that suggests to use alphanumeric ids.