how to use join to join two table in sails - sails.js

I know that in sails i can use populate to join two models like describe in this link Sails model and orm
for example i have 2 model:
// myApp/api/models/Pet.js
module.exports = {
attributes: {
name: {
type: 'string'
},
color: {
type: 'string'
}
}
}
and
// myApp/api/models/User.js
module.exports = {
attributes: {
name: {
type: 'string'
},
age: {
type: 'integer'
},
pony:{
model: 'pet'
}
}
}
then
User.find({ name:'Mike' })
.populate('pony')
.exec(function(err, users) {}
will return something result like
[{
name: 'Mike',
age: 21,
pony: {
name: 'Pinkie Pie',
color: 'pink',
id: 5,
createdAt: Tue Feb 11 2014 15:45:33 GMT-0600 (CST),
updatedAt: Tue Feb 11 2014 15:45:33 GMT-0600 (CST)
},
createdAt: Tue Feb 11 2014 15:48:53 GMT-0600 (CST),
updatedAt: Tue Feb 11 2014 15:48:53 GMT-0600 (CST),
id: 1
}]
in here pony is an object and i don't like that. I want return rerult something like this:
[{
name: 'Mike',
age: 21,
name: 'Pinkie Pie',
color: 'pink',
id: 5,
createdAt: Tue Feb 11 2014 15:45:33 GMT - 0600 (CST),
updatedAt: Tue Feb 11 2014 15:45:33 GMT - 0600 (CST)
createdAt: Tue Feb 11 2014 15:48:53 GMT - 0600 (CST),
updatedAt: Tue Feb 11 2014 15:48:53 GMT - 0600 (CST),
id: 1
}]
(all of them is property). So i think i would need join in this case. how can i do join ?

This question is already covered here. The answer demonstrates using .populate() in Sails for NoSQL DB's and .query() for SQL DB's.
An additional option, if you are using an SQL DB like MySQL, and this is a query that will be run frequently, is to create a view at DB level. You can find more on creating views in the MySql Documentation.

Related

MongoDB Add/Replace Element from Separate Collections

I have two mongodb collections, processes and users and below I have example docs from within them. I am trying to query a process document but replace the userID's that are nested in the event objects with the names of the users instead of their ID's. What is the best way to do that given I may have several nested objects within the 'history' object? (Running on node and using the native driver, not using mongoose).
Process Document
{
_id: ObjectId('63d96b68e7b92dceb334f4cb'),
status: 'active',
history: {
{
type: 'created',
userID: '61e77cdedde2dbe1cbf8a250',
date: 'Tue Jan 31 2023 17:31:32 GMT+0000 (Coordinated Universal Time)'
},
{
type: 'updated',
userID: 'd6xMtHTIX3QO0FifUPgoJLOLz872',
date: 'Tue Jan 31 2023 18:31:32 GMT+0000 (Coordinated Universal Time)'
},
{
type: 'updated',
userID: '61e77cdedde2dbe1cbf8a250',
date: 'Tue Jan 31 2023 19:31:32 GMT+0000 (Coordinated Universal Time)'
},
}
}
User 1 Document
{
_id: ObjectId('d6xMtHTIX3QO0FifUPgoJLOLz872'),
email: 'something#something.com',
firstname: 'Bobby',
lastname: 'Tables',
}
User 2 Document
{
_id: ObjectId('61e77cdedde2dbe1cbf8a250'),
email: 'something2#something.com',
firstname: 'Jenny',
lastname: 'Tables',
}
Actual outpt I'm looking for
{
_id: ObjectId('63d96b68e7b92dceb334f4cb'),
status: 'active',
history: {
{
type: 'created',
userName: 'Jenny Tables',
date: 'Tue Jan 31 2023 17:31:32 GMT+0000 (Coordinated Universal Time)'
},
{
type: 'updated',
userName: 'Bobby Tables',
date: 'Tue Jan 31 2023 18:31:32 GMT+0000 (Coordinated Universal Time)'
},
{
type: 'updated',
userName: 'Jenny Tables',
date: 'Tue Jan 31 2023 19:31:32 GMT+0000 (Coordinated Universal Time)'
},
}
}
Here is what I have tried, which I can get to yield existing data and update one record's name, but not all of them:
try {
const db = mongo.getDB();
const data = db.collection("processes");
data.aggregate([
{$sort: {_id: -1}},
{$lookup: {from: 'users', localField: 'history.userID', foreignField: '_id', as: 'User'}},
{$unwind: '$User'},
{$addFields: {"history.userName": { '$concat': ['$User.firstname', ' ', '$User.lastname']}}},
{$project:{_id: 1, status: 1, history: 1}}
]).toArray(function(err, result) {
if (err)
res.status(500).send('Database array error.');
console.log(result);
res.status(200).send(result);
});
} catch (err) {
console.log(err);
res.status(500).send('Database error.');
}
EDIT:
The former answer is likely correct, the error I'm getting is due to using a uid instead of _id on the user collection (I believe):
Here is my attempt:
data.aggregate([
{$unwind: "$history"},
{"$lookup": {from: "users", localField: "history.userID", foreignField: "uid", as: "userLookup"}},
{$unwind: "$userLookup"},
{$project: {status: 1, history: {type: "$history.type", userName: {"$concat": ["$userLookup.firstname"," ","$userLookup.lastname"]}, date: "$history.date"}}},
{$group: {_id: "$_id",status: {$first: "$status"}, history: {push: "$history"}}},
{"$merge": {into: "process", on: "_id",whenMatched: "merge"}}
]).toArray(function(err, result) {
console.log(result);
if (err)
{
res.status(500).send('Database array error.');
console.log(err);
}
else
res.status(200).send(result);
});
User Document (now):
{
_id: ObjectId('d6xMtHTIX3QO0FifUPgoJLOLz872'),
uid: 'werwevmA5gZ2Ky2MUuSAj6TJiZz1',
email: 'something#something.com',
firstname: 'Bobby',
lastname: 'Tables',
}
You can first $unwind the history array. Perform $lookup to the user collection. Build the new history object. Finally $group back into original form and $merge to update to the collection.
db.processes.aggregate([
{
$unwind: "$history"
},
{
"$lookup": {
from: "users",
localField: "history.userID",
foreignField: "_id",
as: "userLookup"
}
},
{
$unwind: "$userLookup"
},
{
$project: {
status: 1,
history: {
type: "$history.type",
userName: {
"$concat": [
"$userLookup.firstname",
" ",
"$userLookup.lastname"
]
},
date: "$history.date"
}
}
},
{
$group: {
_id: "$_id",
status: {
$first: "$status"
},
history: {
$push: "$history"
}
}
},
{
"$merge": {
into: "process",
on: "_id",
whenMatched: "merge"
}
}
])
Mongo Playground

query to get ids from nested array of object from mongodb

this is data:
[
{
id: 1,
questions: [{
questionID: 11,
createdDate: 2020 - 06 - 22 T14: 07: 22.193 + 00: 00
},
{
questionID: 12,
createdDate: 2020 - 06 - 20 T13: 05: 55.193 + 00: 00
},
{
questionID: 13,
createdDate: 2020 - 06 - 21 T10: 05: 23.193 + 00: 00
}
]
},
{
id: 2,
questions: [{
questionID: 11,
createdDate: 2020 - 06 - 22 T14: 07: 22.193 + 00: 00
}]
}
]
How to get question ids and total number of questions in same query from mongodb using aggregate
.
expected res:
[{
'id': 1,
totalNumberOfQuestions: 3,
ids: [11, 12, 13]
}]
Try this one:
db.collection.aggregate([
{
$project: {
id: 1,
totalNumberOfQuestions: { $size: "$questions" },
ids: "$questions.questionID"
}
}
])

Sails WaterlineORM .populate() with limited attributes

When we use WaterlineORM .populate() query we get all the attributes of the populated association.
eg:
User.find({name:'Finn'}).populate('dad').exec(function (err, usersNamedFinn){
if (err) {
return res.serverError(err);
}
return res.json(usersNamedFinn);
});
Response:
[
{
id: 7392,
age: 13,
name: 'Finn',
createdAt: Wed Dec 25 2003 18:00:00 GMT-0600 (CST),
updatedAt: Wed Feb 12 2016 18:06:50 GMT-0600 (CST),
dad: {
id: 108,
age: 47,
name: 'Joshua',
createdAt: Wed Dec 25 1969 00:00:00 GMT-0600 (CST),
updatedAt: Wed Jan 10 2015 12:00:00 GMT-0600 (CST),
dad: null
}
},
]
I need to get in the response only the name and the id of the populated 'dad' association (i.e. remove the other attributes of dad from the response)
How can I do it?
Detailed information here https://github.com/balderdashy/waterline/issues/919
Seems like it has been added in v0.12.3
populate('relation', { select: ['wantedFields', ...] });
in your Model you can write a toJson() method that will manipulate the object:
toJSON() {
// getting the object...
let obj = this.toObject();
// removing some attributes...
delete obj.createdAt;
delete obj.updatedAt;
return obj;
}
and then into the Controller after the "populated" query results you can do:
.exec(function(err, usersNamedFinn){
if(err){
return res.negotiate(err);
}
return res.json(usersNamedFinn);
});
Hope this could help you

Why we are getting bad hint error on mongodb

We are getting the error as follows:
Tue Mar 31 22:12:17.571 [conn4498842] assertion 10113 bad hint ns:bp_prod079.ECLoginInfo query:{ $query: { ip: "10.10.11.28" }, $hint: true }
Tue Mar 31 22:12:17.571 [conn4498842] assertion 10113 bad hint ns:bp_prod079.ECLoginInfo query:{ $query: { ip: "10.10.11.28" }, $hint: true }
Tue Mar 31 22:12:17.570 [conn4498842] assertion 10113 bad hint ns:bp_prod079.ECLoginInfo query:{ $query: { ip: "10.10.11.28" }, $hint: true }
Tue Mar 31 22:12:17.570 [conn4498842] assertion 10113 bad hint ns:bp_prod079.ECLoginInfo query:{ $query: { ip: "10.10.11.28" }, $hint: true }
Tue Mar 31 22:12:17.569 [conn4498842] assertion 10113 bad hint ns:bp_prod079.ECLoginInfo query:{ $query: { ip: "10.10.11.28" }, $hint: true }
Tue Mar 31 22:12:17.568 [conn4498842] assertion 10113 bad hint ns:bp_prod079.ECLoginInfo query:{ $query: { ip: "10.10.11.28" }, $hint: true }
Tue Mar 31 22:12:17.568 [conn4498842] assertion 10113 bad hint ns:bp_prod079.ECLoginInfo query:{ $query: { ip: "10.10.11.28" }, $hint: true }
Tue Mar 31 22:12:17.567 [conn4498842] assertion 10113 bad hint ns:bp_prod079.ECLoginInfo query:{ $query: { ip: "10.10.11.28" }, $hint: true }
Tue Mar 31 22:12:17.566 [conn4498842] assertion 10113 bad hint ns:bp_prod079.ECLoginInfo query:{ $query: { ip: "10.10.11.28" }, $hint: true }
Tue Mar 31 22:12:17.566 [conn4498842] assertion 10113 bad hint ns:bp_prod079.ECLoginInfo query:{ $query: { ip: "10.10.11.28" }, $hint: true }
Tue Mar 31 22:12:17.565 [conn4498842] assertion 10113 bad hint ns:bp_prod079.ECLoginInfo query:{ $query: { ip: "10.10.11.28" }, $hint: true }
Tue Mar 31 22:12:17.565 [conn4498842] assertion 10113 bad hint ns:bp_prod079.ECLoginInfo query:{ $query: { ip: "10.10.11.28" }, $hint: true }
Tue Mar 31 22:02:09.796 [conn4504767] assertion 10113 bad hint ns:bp_prod079.BPNote query:{ $query: { admission: ObjectId('54c1ef1b241c90eb1a8b457a') }, $hint: true }
Tue Mar 31 22:02:09.795 [conn4504767] assertion 10113 bad hint ns:bp_prod079.BPNote query:{ $query: { admission: ObjectId('54c1ef1b241c90eb1a8b457a') }, $hint: true }
Tue Mar 31 22:02:09.795 [conn4504767] assertion 10113 bad hint ns:bp_prod079.BPNote query:{ $query: { admission: ObjectId('54c1ef1b241c90eb1a8b457a') }, $hint: true }
Tue Mar 31 22:02:09.794 [conn4504767] assertion 10113 bad hint ns:bp_prod079.BPNote query:{ $query: { admission: ObjectId('54c1ef1b241c90eb1a8b457a') }, $hint: true }
Tue Mar 31 22:02:09.793 [conn4504767] assertion 10113 bad hint ns:bp_prod079.BPNote query:{ $query: { admission: ObjectId('54c1ef1b241c90eb1a8b457a') }, $hint: true }
Tue Mar 31 22:02:09.793 [conn4504767] assertion 10113 bad hint ns:bp_prod079.BPNote query:{ $query: { admission: ObjectId('54c1ef1b241c90eb1a8b457a') }, $hint: true }
Tue Mar 31 22:02:09.792 [conn4504767] assertion 10113 bad hint ns:bp_prod079.BPNote query:{ $query: { admission: ObjectId('54c1ef1b241c90eb1a8b457a') }, $hint: true }
Tue Mar 31 22:02:09.791 [conn4504767] assertion 10113 bad hint ns:bp_prod079.BPNote query:{ $query: { admission: ObjectId('54c1ef1b241c90eb1a8b457a') }, $hint: true }
bad hint ns:bp_prod079.ECLoginInfo query:{ $query: { ip: "10.10.11.28" }, $hint: true }
It looks like, somewhere in your code, you're querying the bp_prod079.ECLoginInfo collection like
use EBLoginInfo
db.ECLoginInfo.find({ "ip" : "10.10.11.28" }).hint(true)
which means somebody doesn't know what $hint does. $hint expects you to give an index name or specification for the query, e.g.
db.ECLoginInfo.find({ "ip" : "10.10.11.28" }).hint({ "ip" : 1 })
You need to find where in your code $hint is being used incorrectly and either fix the hint or get rid of it. There should be no need for a hint on such simple queries.

Mongoose: Saving an instance of my Model creates two entries in MongoDB

My Code:
var mySchema = new Schema({
aktuell: {N7:String, Auftragsnr:String},
historie : [new Schema({
date: { type: Date, default: Date.now },
changed: {N7:String, Auftragsnr:String},
deleted: { type: Boolean, default: false }
}, {_id:false})]
}, { strict: false });
createIP = function(req, res) {
var ip = new IP ({
aktuell: req.body.aktuell,
historie: [
{
date: nowObj,
changed: req.body.aktuell
}
]
});
ip.save(function(err) {
if(err) {
res.send({status:err});
return;
} else {
res.send({ status: 'OK', ip:ip });
}
});
}
I expect it to create such entry in my DB:
{ _id: 54181fc0c5b9c1c7294ef510,
historie:
[ { deleted: false,
changed: [Object],
date: Tue Sep 16 2014 13:32:16 GMT+0200 (CEST)
} ],
aktuell: { Auftragsnr: '12', N7: '123132' } }
But in addition to above object literal an additional historie object gets created with its own ObjectId. This is why I used {_id:false} in my model. I also declared my array as new Schema as advised by the Mongoose Docs. I am out of knowlodge, I tried so much. How to get rid of this bug?
A console.log(ip) shows that indeed two object literals are passed by mongoose to mongoDD, one with an empty aktuell object, and one with a filled one. Also the changed object behaves strangely. What is going on here?
Im listening on port 9000
Connected to Database
POST - /ip/create
{ __v: 0,
_id: 54182c3bd9d529df6085f853,
historie:
[ { deleted: false,
changed: {},
date: Tue Sep 16 2014 14:25:31 GMT+0200 (CEST) } ],
aktuell: {} }
IP created
POST /ip/create/ 200 25.763 ms - 128
POST - /ip/create
{ __v: 0,
_id: 54182c3bd9d529df6085f854,
historie:
[ { deleted: false,
changed: [Object],
date: Tue Sep 16 2014 14:25:31 GMT+0200 (CEST) } ],
aktuell: { Auftragsnr: '14', N7: 'qweqw' } }
IP created
POST /ip/create/ 200 23.870 ms - 214
If you don't want an id on your nested documents and don't want to access them outside your ip object you don't need to create another schema for it. A new schema usually means a new collection and a reference to it. Instead, just have it be nested:
var IpSchema = new Schema({
aktuell: {
N7: { type: String },
Auftragsnr: { type: String },
},
historie: [
{
_id: false,
date: { type: Date, default: Date.now },
changed: {
N7: { type: String },
Auftragsnr: { type: String },
},
deleted: { type: Boolean, default: false },
}
],
});
Think this will also solve your problem, let me know.