Loopback [nodejs] automigrate/auto-updating model to mongodb - node.js

New to loopback and and I can't for the life of me migrate a single json model to my mongodb data source.
I've been fussing about with: https://docs.strongloop.com/display/public/LB/Creating+a+database+schema+from+models
And here's what I've tried so far:
I created a migration script bin/migrate.js which I plan on running every time I need to migrate changes using auto-update:
var path = require('path');
var app = require(path.resolve(__dirname, '../server/server'));
var ds = app.datasources.acme;
var appModels = ['Client'];
ds.isActual(appModels, function(err, actual) {
if (!actual) {
ds.autoupdate(appModels, function(err) {
if (err){
throw (err);
}
});
}
});
console.log("Migrated: " + appModels.join());
I checked both using robomongo and the mongo cli and I can't find the generated table:
> use acme
switched to db acme
> db.getCollectionNames();
[ ]
I'm also new to mongodb so there may be something wrong as well in how I'm checking if the migration succeeded.
I've tried the answer here but it didn't work for me: Migrating built-in models to Databases
Some other pertinent stuff:
datasources.json
{
"acme": {
"host": "127.0.0.1",
"port": 27017,
"database": "acme",
"username": "root",
"password": "password",
"name": "acme",
"connector": "mongodb",
"user": "root"
}
}
My model
{
"name": "Client",
"plural": "Clients",
"base": "User",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"contact_number": {
"type": "string"
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": {}
}

Turns out that this was actually working. Coming from a mysql background, I didn't know that the you can only see a mongodb collection once there are documents inside it.
I got the visual confirmation I was looking for when I added the following:
app.models.Client.create([
{contact_number: '09xxxxxxx', password: 'password', email: 'acme#gmail.com'},
], function(err, clients) {
if (err){
throw err;
}
console.log('Models created: \n', clients);
});

Related

How to update a value inside mongodb with nodeJS?

I'm trying to update a value inside mogoodb array but is the problem
database?
"TempChannels": [{
"user": "299481590445113345",
"channel": "794869948878159884",
"settings": []
}, {
"user": "583363766750806043",
"channel": "795004103998308352",
"settings": []
}],
The part of the code that should update the user:
Data.TempChannels[0].user = Target.id
Data.save().catch(er => console.log(er))
Also, no error appears when I run the code. and when i console the data it returns a user which has updated but it is not actually saved in mongodb!
code
Data.save().then(() => console.log(Data.TempChannels[0].user))
this is the whole data
{
"_id": {
"$oid": "5ff0cd1ee3d9fd2d40d82d23"
},
"TempChannels": [{
"user": "299481590445113345",
"channel": "795014692522295326",
"settings": []
}, {
"user": "583363766750806043",
"channel": "795015273060892753",
"settings": []
}],
"Guild": "704158258201624657",
"Stats": "true",
"ChannelID": "795014681664290826",
"ParentID": "795014680556994610",
"LogChannelID": "795014683601010709",
"TempControlChannelID": "795014682518749274",
"DefaultSettings": {
"limit": null,
"name": null,
"bitrate": null,
"copyperms": null
},
"__v": 2
}
I'm filtering the data by Guild
if you are using mongoose to connect MongoDB, the
Use markModified("updated field name")
Data.TempChannels[0].user = Target.id
Data.markModified('TempChannels');
Data.save().catch(er => console.log(er))
if you are using mongoose, there is a method that will allow to update the content of existing data
const res = await Person.replaceOne({ _id: 24601 }, { name: 'Jean Valjean' });
res.n; // Number of documents matched
res.nModified; // Number of documents modified
If you are using Mongoose, you can update the record by doing something similar to this:
SchemaName.update({Guild: 'Guild Value Here'}, {$set: { "TempChannels[0].user" : "%newvalue%"}})
.then((data) => {
console.log(data)
})
.catch(err => {
console.log.error(err);
});
You should replace schemaName with the name of your schema if you are using mongoose, and in case you are not using it, I think it would be better for you to start using it.

Loopback + mongoDB: Can't find extended user

I am using Loopback 3.0 with MongoDB connector.
In a REST method exposed somewhere, I need to access the currently logged user and make some updates on it.
I have extended the base User model, calling it appUser, the login works, and I can get the token (after I changed the token model to point to the appUser) of a logged user. The model is the following one:
{
"name": "appUser",
"plural": "appUsers",
"base": "User",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"gender": {
"type": "string",
"enum": [
"M",
"F"
]
},
"birthDate": {
"type": "Date"
}
},
"validations": [],
"relations": {},
"acls": []
}
I need to access the user profile, in order to update it. But when I query it, I get null as result.
const User = app.models.appUser;
User.findOne({
where: {
_id: ObjectId("5aae7ecd2ed1b11b1c09cf25")
}
}, (err, user) => {
if (err || res == null) {
console.log("Error updating the user ");
const error = {
"name": "Database error",
"status": 500,
"message": "Can't access the database."
}
callback(error, null, null);
} else {
//Whatever
}
});
But if I run the same query from Robo3T on MongoDB, it works.
db.getCollection('appUser').find({"_id": ObjectId("5aae7ecd2ed1b11b1c09cf25")})
What am I doing wrong?
Thank you,
Massimo
You didn't call the user so that should be the case, also in your callback you are passing null and not your user result. However I don't get where the res variable came from.
const User = app.models.appUser;
User.findOne({
where: {
_id: ObjectId("5aae7ecd2ed1b11b1c09cf25"),
}
}, (err, user) => {
if (err) {
console.log("Error updating the user", err); // logs the app error
const error = {
"name": "Database error",
"status": 500,
"message": "Can't access the database."
}
callback(error, null); // passes your custom error
}
console.log("APP USER", user);
callback(null, user);
});
I don't how you calling your callback but i think you can manage this.
If you still have no result try changing _id to id

Adding fields to a nested document in mongoDB using Node js mongoDB driver

I wanted to know how to write a update for mongoDB using the Node js driver with the requirement as below
My document in a collection is as such
{
"_id": {
"$oid": "5a4e098e734d1d089c5a7473"
},
"username": "guest",
"password": "guest",
"categories": {
"movie": [
"Minions",
]
}
}
Now i want to add a new field in categories named games with an array as its value for a particular username
i wrote the query as below but it didn't work
db.collection('userdata').aggregate([ { '$match': { "username": "guest" } },{ '$addFields ': { "catagories.games" : [] }}],function(err, docs) {
assert.equal(null, err);
console.log(docs);
});
I want to know where am i going wrong or how to solve this issue
u can use update feature of mongodb
db.userdata.update(
{ "username": "guest" },
$set:{
"catagories.games" : []
},
{ upsert: true }
)
upsert true means if not exist,then insert
source-https://docs.mongodb.com/manual/reference/method/db.collection.update/

nodejs/loopback: defining relationships doesn't seem to be reflected on database?

I am creating an API with strongloop loopback.
I have defined my models, and basically all is good there.
But I have a problem understanding how loopback deals with relationships.
Not all of my relationships I defined seem to really be reflected in the database and the interface.
For example, I have a model song, it
hasAndBelongsToMany albums
hasAndBelongsToMany playlists
hasAndBelongsToMany userplaylists
belongsTo artist
Here is /common/models/song.json
{
"name": "song",
"plural": "song",
"base": "PersistedModel",
"idInjection": true,
"properties": {
//some more properties of song
},
"validations": [],
"relations": {
"albums": {
"type": "hasAndBelongsToMany",
"model": "album",
"foreignKey": ""
},
"artist": {
"type": "belongsTo",
"model": "artist",
"foreignKey": ""
},
"playlists": {
"type": "hasAndBelongsToMany",
"model": "playlist",
"foreignKey": ""
},
"userplaylists": {
"type": "hasAndBelongsToMany",
"model": "userplaylist",
"foreignKey": ""
}
},
"acls": [],
"methods": []
}
But when I look at the postgresql table generated, I see:
title | character varying(1024) | not null
id | integer | not null default nextval('song_id_seq'::regclass)
#some other properties of song
artistid | integer |
Accordingly, the interface in loopbacks explorer at localhost:3000/explorer says:
post /song
Response Class
Model
Model Schema
{
"title": "",
//some other properties of song
"id": 0,
"artistId": 0
}
The question: Shouldn't there also be a songs, a playlists and a userplaylists variable??? Or have I been working too much in the NoSql world and now I forgot how to handle relationships?
BTW. I have a migrate script which I executed when adding the relationships to the models:
var path = require('path');
var app = require(path.resolve(__dirname, '../server'));
var dataSource = app.dataSources.cantoalegre_ps_DS;
dataSource.automigrate(function(err) {
if (err) {
console.log("Error migrating models: " + err);
}
else {
console.log("Successfully migrated models");
}
process.exit();
});
usually related data has the foreign key:
customer,
order belongs to customer so order has a column that contains the customer id.
Take care that at every change models have to be synchronized to the db by an autoupdate script.
module.exports = function(app) {
var ds = app.dataSources.pg;
ds.isActual('mymodel', function(err, actual) {
if (!actual) {
ds.autoupdate('mymodel', function(err, result) {
console.log("AUTOUPDATE mymodel",err,result);
});
}
});
};

Trouble using mongodb $ positional indicator in nodejs with monk.js

I am trying to perform a search on my database and return the roles a user has for an application and store that in their session.
The end state being in their session I now have user.applications =
[
{
"_id": "oehgf12083310f1h30f",
"name": "Internal",
"roles": {
"send": true,
"create_template": true,
"edit_template": true
}
}
]
The applications data structure:
[
{
"_id": "oehgf12083310f1h30f",
"name": "Internal",
"permissions": [
{
"username": "username2",
"roles": {
"send": true,
"create_template": true,
"edit_template": true
}
},
{
"username": "username1",
"roles": {
"send": true,
"create_template": true,
"edit_template": false
}
}
]
}
]
Using the mongodb console
I can perform this search and returns exactly what I need to populate the user.applications object in their session:
db.applications.find({
"permissions.username": "username2"
}, {
"permissions.$": true,
name: true
}).pretty()
This returns all applications that username2 has access to, while returning the level of permissions they have, and only them. So excludes username1 object
In nodejs using monk
find({
"permissions.username": "username2" || req.query.username
}, {
"permissions.$": true,
name: true
}, function(err, docs) {});
Now this search returns the user objects for username2 AND username1, which is problematic as I then have to process that even further to extract the correct permissions.
Questions
I suspect monk does something to my search that leaves it unable to use the $ positional indicator, but if I am wrong, please let me know how I can use it to achieve what I am after.
Otherwise any other ideas/approaches I could that to achieve that end state would be greatly appreciated :)
Maybe this helps:
find({permissions.username": "username2" || req.query.username }, { "permissions": { "$elemMatch": {"username": "username2"}}, name: true}, function(err, docs) {});

Resources