Loopback 4/MongoDB - Foreign key not converted to ObjectID - mongodb

I am trying to set up an hasMany relation using a Mongo database.
I have followed the guide to create an hasMany relation in the loopback 4 documentation (https://loopback.io/doc/en/lb4/HasMany-relation.html) and tryied to set differents properties but the foreign key custId is saved as a string and not as an ObjectID.
I also found a few other properties or options from others topics but people were using Loopback 3 and it doesn't seem to work with Loopback 4.
Did I miss something or is there any workaround ?
Here are my models :
#model()
export class Order extends Entity {
#property({
type: 'string',
id: true,
generated: true,
})
id: string;
#property({
type: 'array',
itemType: 'string',
required: true,
})
product: string[];
#property({
type: 'number',
required: true,
})
price: number;
#property({
type: 'string',
id: true,
generated: true,
})
custId: string;
constructor(data?: Partial<Order>) {
super(data);
}
}
#model()
export class Customer extends Entity {
#property({
type: 'string',
id: true,
generated: true,
})
id: string;
#property({
type: 'string',
required: true,
})
name: string;
#property({
type: 'string',
})
adress?: string;
#hasMany(() => Order, {keyTo: 'custId'})
orders?: Order[];
constructor(data?: Partial<Customer>) {
super(data);
}
}

This is currently a bug. The hasMany / belongsTo will end up saving the relation id as a string instead of an ObjectId. You can verify this by changing the id in the database directly to an ObjectId and then it will find it.
Reference: https://github.com/strongloop/loopback-next/issues/2085
It is also mentioned on the latest Monthly Milestone here, so hopefully it will be resolved soon: https://github.com/strongloop/loopback-next/issues/2313
Edit: I was able to get it working by adding strictObjectIDCoercion to the model, but that can break other things according to issue 2085 linked above.
#model({
settings: {
strictObjectIDCoercion: true,
}
})

For hasMany relationship you need to update order Model.
Update order.model with :
1.Import Customer Model
import {Customer} from './customer.model';
remove custId: string;
2.For reference customer Id Just update code with
#belongsTo(() => Customer)
custId: number;
Reference Example : here

Related

Data type Object is not supported by Postgres database. NestJS

#Column({ nullable: true })
Test: number | string;
Why is the above returning an object? The data type can be either string or number.
Thanks
#Column({ type: 'character varying' || 'integer', nullable: true })
Test: number | string;
The above made it work.

TypeORM doesn't support the database setting on the entity decorator

I'm trying to seperate my TypeORM project over multiple databases as it is growing in size, and its components are very discrete(yet interlinked, so i need to be able to have relations cross-database).
I am trying to do that using the database setting on the #Entity decorator, as described here: https://typeorm.io/#multiple-connections/using-multiple-databases-in-a-single-connection
I made a minimal reproducable example for this, with two entities that should in theory be put in different databases:
#Entity({ database: 'test' })
export default class Entity1 {
#PrimaryGeneratedColumn()
id?: number
#Column()
name?: string
#Column()
address?: string
}
and
#Entity({ database: 'database2' })
export default class Entity2 {
#PrimaryGeneratedColumn()
id?: number
#Column()
name?: string
#Column()
address?: string
}
Connection code:
import {createConnections} from "typeorm";
async function doDbExample() {
const connections = await createConnections([{
name: "db1Connection",
type: "postgres",
host: "db",
port: 5432,
username: "test",
password: "testPassword",
database: "test",
entities: [__dirname + "/entity/*{.js,.ts}"],
synchronize: true
}]);
console.log("Created connections")
}
doDbExample()
However, what happens is that both entities' table is put in the database of the connection. Am i doing something wrong, or is this a bug in TypeORM? It looks to me like it is not respecting the database setting any more.
I am running the code using ts-node-dev
I made a full minimal reproducable example, complete with dockerized setup of the database environment, on github: https://github.com/petterroea/TypeOrmBug-MRE
This is a setup issue. I solved it like this:
Modify the array entities so each connection/database has its own folder with entity files and name the entity you use the most as default:
// src/index.ts
await createConnections([
{
name: 'default',
host: 'SERVER1',
username: 'bob',
password: 'kiwi,
type: 'mssql',
database: 'db1',
...
"synchronize": true,
"entities": ["src/db1/entity/**/*.ts"],
},
{
name: 'connection2,
host: 'SERVER2',
username: 'Mike',
password: 'carrot',
type: 'mssql',
database: 'db2,
...
"synchronize": true,
"entities": ["src/db2/entity/**/*.ts"],
])
Create entity files for each database in its respective folder:
src/db1/entity/Fruit.ts > table in db1
src/db2/entity/Vegetables.ts > table in db2
With "synchronize": true each table will be created automatically in the correct database
Accessing data in the tables:
For the default connection::
import { Fruit} from 'src/db1/entity/Fruit.ts'
fruits() {
return Fruit.find()
}
For the non default connection:
import { getRepository } from 'typeorm'
import { Vegetable} from 'src/db2/entity/Vegetable.ts'
vegetables() {
return async () => await getRepository(Vegetable).find()
}
or
async vegetables() {
return await getRepository(vegetables, 'connection2').find()
}
I hope this helps someone else struggling with the same issues as you and me.

Meteor - node simple schema validate data to match schema

I want to change my Rest-API validation to node simple schema for schema definition and collection2#core for schema validation.
I want to use the Person schema to validate the data provided by the users.
Schemas = {};
Schemas.Person = new SimpleSchema({
name: {
type: String,
label: "Person's Name",
unique: true,
max: 200
},
surname: {
type: String,
unique: true,
label: "person's surname"
},
};
validData = API.utility.validate(data, Schemas.Person });
API: {
utility: {
validate: function(data, schema) {
return "The SimpleSchema Validation";
}
}
};
This case is described in the simpl-schema documentation
With your schema definition you can just do:
Schemas.person.validate(data);
If right after that you want to look at the result or the errors:
Schemas.person.isValid();
Schemas.person.validationErrors();

ER_TOO_LONG_KEY in SailsJS 1.0 with sails-mysql

I got this error with sails when I try to sails lift:
info: ·• Auto-migrating... (drop)
error: A hook (`orm`) failed to load!
error:
error: Error: ER_TOO_LONG_KEY: Specified key was too long; max key length is 767 bytes
I just have one model for now: 
module.exports = {
datastore: 'default',
tableName: 'sci_user',
attributes: {
email: {
type: 'string',
required: true,
unique: true
},
password: {
type: 'string',
required: true
}
}
It's really simple and I got it from the documentation. I don't understand. It seems it's because of the unique: true.
This is due to a combination of factors, but the most pertinent one is that sails-mysql currently defaults to using the utf8mb4 character set for string attributes, to allow the use of emojis and other extended characters. We're working on a patch to make this configurable rather than the default, but in the meantime the quickest workaround is to declare the columnType for your attributes directly:
module.exports = {
datastore: 'default',
tableName: 'sci_user',
attributes: {
email: {
type: 'string',
required: true,
unique: true,
columnType: 'varchar'
},
password: {
type: 'string',
required: true,
columnType: 'varchar'
}
}

Sailsjs Model Object Not Returning Data For Postgresql

I have the following in my Sailsjs config/adapter.js:
module.exports.adapters = {
'default': 'postgres',
postgres : {
module : 'sails-postgresql',
host : 'xxx.compute-1.amazonaws.com',
port : 5432,
user : 'xxx',
password : 'xxx',
database : 'xxx',
ssl : true,
schema : true
}
};
And in models/Movie.js:
Movie = {
attributes: {
tableName: 'movies.movies',
title: 'string',
link: 'string'
}
};
module.exports = Movie;
In my controller:
Movie.query("SELECT * FROM movies.movies", function(err, movies) {
console.log('movies', movies.rows);
});
movies.rows DOES return the correct data
However:
Movie.find({ title: 'Frozen' }, function(err, movies) {
console.log('movies', movies)
});
movies returns an EMPTY ARRAY
So it seems all connections are good because the raw query works perfectly.
Could there be something I am doing wrong with setting up the Movie.find() or with models/Movie.js?
Does the tableName attribute not support postgresql schema_name.table_name?
First off, you need to move tableName out of attributes, since it's a class-level property. Second, sails-postgresql does have some (very undocumented) support for schemas, using the meta.schemaName option:
Movie = {
tableName: 'movies',
meta: {
schemaName: 'movie'
},
attributes: {
title: 'string',
link: 'string'
}
};
module.exports = Movie;
You can give that a try, and if it doesn't work, either move your table into the public schema, or nudge the author of the schemaName support for help.