How to get data from different schema in Nodejs - node.js

I have two schemas called employees (parent) and assessments(child)
Every assessment will have a pass percentage of employee id
so I have results like this
employees : [
{
"_id": 12345,
"name": "David",
"evaluated": false
},
{
"_id": 12346,
"name": "Miller",
"evaluated": false
}
]
Second Schema
assessments: [
{
"assessment_type": "basic",
"employee_id": 12345,
"qualified": true
},
{
"assessment_type": "advanced",
"employee_id": 12345,
"qualified": false
},
{
"assessment_type": "basic",
"employee_id": 12346,
"qualified": true
},
{
"assessment_type": "advanced",
"employee_id": 12346,
"qualified": true
}
]
So I want to get the employees with evaluated based on assessments qualified is true
can you please tell me what is the best approach for this?

Here is an example where we sort the employees by the assements they succeeded.
const employees = [{
_id: 12345,
name: 'David',
evaluated: false,
}, {
_id: 12346,
name: 'Miller',
evaluated: false,
}];
const assessments = [{
assessment_type: 'basic',
employee_id: 12345,
qualified: true,
}, {
assessment_type: 'advanced',
employee_id: 12345,
qualified: false,
}, {
assessment_type: 'basic',
employee_id: 12346,
qualified: true,
}, {
assessment_type: 'advanced',
employee_id: 12346,
qualified: true,
}];
// Loop at the employees
const sortByAssessment = employees.reduce((tmp, x) => {
// Get all the assessment about the employee
const employeeAssessment = assessments.filter(y => y.employee_id === x._id);
// Deal with each assessment
employeeAssessment.forEach((y) => {
// Only do something about successfull assessments
if (y.qualified) {
// In case this is the first time we are dealing with the assessment_type
// create an array where we are going to insert employees informations
tmp[y.assessment_type] = tmp[y.assessment_type] || [];
// Push the name of the employee inside of the assessment type array
tmp[y.assessment_type].push(x.name);
}
});
return tmp;
}, {});
console.log(sortByAssessment);

you can do 2 things join with $look up or populate with employee id
assessments.aggregate([
{
'$lookup': {
'from': 'employees',
'localField': 'employee_id',
'foreignField': '_id',
'as': 'datas'
}
},
{ "$unwind": "$datas" },
].exec(function(err,result){
console.log(result)
});
2nd way
//assessments your model name
assessments.populate('employee_id').exec(function(err,result){
console.log(result);
});

Related

How to set "seen:true" in array of messages in mongoose

I am newbie in mongodb world, i was stuck in on Mongoose query.
basically I was developing a chat application for my website. the chat schema of my website shown below
const LiveChat = mongoose.Schema({
members: [String],
messages: [{
sender: String,
reciever: String,
text: String,
seen: {
type: Boolean,
default: false
},
date: {
type: Date,
default: Date.now
}
}],
}, { timestamps: true });
for exapmle collection will looks like this
[
{
"_id":"627749f8dc5927d660f76172",
"members":[
"626a250d11ed1b096883aed1",
"626a234611ed1b096883ae13"
],
"messages":[
{
"sender":"626a250d11ed1b096883aed1",
"reciever":"626a234611ed1b096883ae13",
"text":"hello there!.",
"seen":false,
"_id":"6278b0c38031894a9ceefeae",
"date":"2022-05-09T06:12:19.857Z"
},
{
"sender":"626a250d11ed1b096883aed1",
"reciever":"626a234611ed1b096883ae13",
"text":"how are you?.",
"seen":false,
"_id":"6278b0e18031894a9ceefede",
"date":"2022-05-09T06:12:49.680Z"
},
{
"sender":"626a234611ed1b096883ae13",
"reciever":"626a250d11ed1b096883aed1",
"text":"hello Rupesh",
"seen":false,
"_id":"6278b1438031894a9ceeff98",
"date":"2022-05-09T06:14:27.388Z"
},
{
"sender":"626a234611ed1b096883ae13",
"reciever":"626a250d11ed1b096883aed1",
"text":"we are doing well",
"seen":false,
"_id":"6278b1588031894a9ceeffe0",
"date":"2022-05-09T06:14:48.203Z"
},
{
"sender":"626a250d11ed1b096883aed1",
"reciever":"626a234611ed1b096883ae13",
"text":"okay",
"seen":false,
"_id":"6278b1ed8031894a9cef0099",
"date":"2022-05-09T06:17:17.421Z"
}
],
"createdAt":"2022-05-08T04:41:28.416Z",
"updatedAt":"2022-05-09T06:17:17.420Z",
"__v":0
},
{
"_id":"62762021be68a5e2de8dc2d2",
members: ["626a250d11ed1b096883aed1", "6273bc879ff276ac89f9c4f8"]
"messages":[
{
"sender":"626a250d11ed1b096883aed1",
"reciever":"6273bc879ff276ac89f9c4f8",
"text":"hello there!",
"seen":false,
"_id":"6277ac0ba5fe501f98e1421e",
"date":"2022-05-08T11:39:55.263Z"
},
{
"sender":"626a250d11ed1b096883aed1",
"reciever":"6273bc879ff276ac89f9c4f8",
"text":"can you please tell me what is the date of start a project task",
"seen":false,
"_id":"6277ac30a5fe501f98e1424c",
"date":"2022-05-08T11:40:32.472Z"
},
],
"createdAt":"2022-05-07T07:30:41.447Z",
"updatedAt":"2022-05-08T12:24:31.400Z",
"__v":0
}
]
now i want to set seen:true for all messages into messages array whose sender == "626a250d11ed1b096883aed1" ( sender_id and conversation_id are given from req.body into a API).
for all messages in messages array:
seen:false means message is not seen by reciever
seen:true means message is seen by reciever
i was trying following way into my express API but its not wokring...
cosnt {conversation_id, sender_id} = req.body;
LiveChat.findByIdAndUpdate({ _id: conversation_id },
[{
$set: {
'messages.seen': { $cond: [{ $eq: ['messages.sender', sender_id] }, true, false] }
}
}]
,
{
new: true,
useFindAndModify: true,
}
please help me to write this query...
Here's one way you could do the update using "arrayFilters".
db.collection.update({
"_id": "627749f8dc5927d660f76172" // given _id
},
{
"$set": {
"messages.$[x].seen": true
}
},
{
"arrayFilters": [
{
"x.sender": "626a250d11ed1b096883aed1" // given sender
}
]
})
Try it on mongoplayground.net.

Mongoose populate 3 deep nested schema with JSON response

I have a find() query that when executed, I can see the json with the nested schemas that I want to see except for the 'artista' attribute only displays the id, instead of the properties I want. See below:
{
"total": 1,
"ordenes": [
{
"artpieces": [
{
"_id": "60c1388f30316c02b9f6351f",
"artista": "60c055736c7ca511055a0e1a",
"nombre": "LILIES"
},
{
"_id": "60c12fca30316c02b9f63519",
"nombre": "GERNICA",
"artista": "60c136bf30316c02b9f6351b"
}
],
"_id": "60c414f9ea108a14ef75a9fb",
"precio": 3000,
"usuario": {
"_id": "609c0068e67e68",
"nombre": "Arturo Filio"
}
}
]
}
The query I use to get the json above:
const [total, ordenes] = await Promise.all([
Orden.countDocuments(),
Orden.find()
.populate("usuario", "nombre")
.populate("artpieces", ["nombre","artista","nombre"])
]);
res.json({
total,
ordenes
});
It's an order schema that has artpieces. Each artpiece (I called it 'producto'), has a name a genre, an author/artist and the user which the order belongs to.
my Schema for the orden.js:
const { Schema, model } = require('mongoose');
const OrdenSchema = Schema({
artpieces: [
{
type: Schema.Types.ObjectId,
required: true,
ref: 'Producto'
}
],
estado: {
type: Boolean,
default: true,
required: true
},
usuario: {
type: Schema.Types.ObjectId,
ref: 'Usuario',
required: true
},
precio: {
type: Number,
required: true
}
})
OrdenSchema.methods.toJSON = function () {
const { __v, estado, ...data} = this.toObject();
return data;
}
module.exports = model('Orden', OrdenSchema);
Last thing I want to mention, I know for a fact that I have the code necessary in the artista.js model to display the name of the artist because I have a similar query to display all the artpieces with each artpiece have a genre and an artist.
That example looks like so (to give context):
{
"total": 4,
"productos": [
{
"precio": 0,
"_id": "60c12fca30316c02b9f63519",
"nombre": "GERNICA",
"categoria": {
"_id": "60c04e3605d3c10ed10389e4",
"nombre": "NEO CUBISMO"
},
"artista": {
"_id": "60c136bf30316c02b9f6351b",
"nombre": "PICASSO"
},
"usuario": {
"_id": "609c8c0068e67e68",
"nombre": "Arturo Filio"
}
}
]
}
What am I doing wrong that I can't get my json result at the top look like the json at the bottom, where the artist attribute is?
Also just to point out, I have checked how to nest populate methods in order SO posts including the path and the ref to the Schema and still haven't been able to get the expected result.

join same table in sequelize and print in excel

I want to print parent name in excel
this is my code
function getReportT0Print(req, res) {
return new Promise((resolve, reject) => {
Product.findAll({
where: {
$and: [
{
public: true,
visible: true,
ancestry: {
$not: null,
},
},
],
},
include: [
{
model: ormDb.Document,
required: false,
},
],
attributes: ["name", "slug", "folder_path"],
})
.then(function (data) {
// console.log("data" + data.length);
var rows = [];
rows.push(["Product Name", "Slug", "File Path", "Product Parent Name"]);
data.map(function (product) {
rows.push([
product.name,
product.slug,
product.folder_path,
(here i need to print parent name)
]);
});
var workbook = new Excel.Workbook();
var sheet = workbook.addWorksheet("products_with_tags");
sheet.addRows(rows);
resolve(workbook);
return res.send("successfull");
})
.catch(function (err) {
reject(err);
});
});
}
i can print name, slug,folder_path but i don't know how to print parent name in excel file
as parent name is not present but i have given parent_id in place of parent name and want to print parent name
my SQl table look like this
("id" "name" "version" "published" "reviewed" "visible" "public", "parent_id")
You need to register an association between two Product models like this:
Product.belongsTo(Product, { foreignKey: 'parent_id', as: 'parent' });
You can place it in some module outside model's module file where you create Sequelize instance, for example.
To use this association you need to use the same include option as you did with Document:
Product.findAll({
where: {
$and: [
{
public: true,
visible: true,
ancestry: {
$not: null,
},
},
],
},
include: [
{
model: Product,
as: 'parent',
required: false, // or true if parent_id is required field
// or you wish to get all products with parents
attributes: ["name", "slug", "folder_path"],
},
{
model: ormDb.Document,
required: false,
},
],
attributes: ["name", "slug", "folder_path"],
})

How to insert multiple JSON document in elastic search

Input Data
[{
"_index": "abc",
"_type": "_doc",
"_id": "QAE",
"_score": 6.514091,
"_source": {
"category": "fruits",
"action": "eating",
"metainfo": {
"hash": "nzUZ1ONm0e167p"
},
"createddate": "2019-10-03T12:37:45.297Z"
}},
{
"_index": "abc",
"_type": "_doc",
"_id": "PQR",
"_score": 6.514091,
"_source": {
"category": "Vegetables",
"action": "eating",
"metainfo": {
"hash": "nzUZ1ONm0e167p"
},
"createddate": "2019-10-03T12:37:45.297Z"
}
}-----------------
----------------]
I have around 30,000 records as input data. How to insert this data in a single query. I tried by
var elasticsearch = require('elasticsearch');
var client = new elasticsearch.Client({
host: '********',
log: 'trace'
});
client.index({
index: "abc",
body: ****input data*****
}).then((res) => {
console.log(res);
}, (err) => {
console.log("err", err);
});
In this code, send input data in the body. but it returns an error. Please suggest to me.
This seems like what are you looking for:
'use strict'
require('array.prototype.flatmap').shim()
const { Client } = require('#elastic/elasticsearch')
const client = new Client({
node: 'http://localhost:9200'
})
async function run () {
await client.indices.create({
index: 'tweets',
body: {
mappings: {
properties: {
id: { type: 'integer' },
text: { type: 'text' },
user: { type: 'keyword' },
time: { type: 'date' }
}
}
}
}, { ignore: [400] })
const dataset = [{
id: 1,
text: 'If I fall, don\'t bring me back.',
user: 'jon',
date: new Date()
}, {
id: 2,
text: 'Winter is coming',
user: 'ned',
date: new Date()
}, {
id: 3,
text: 'A Lannister always pays his debts.',
user: 'tyrion',
date: new Date()
}, {
id: 4,
text: 'I am the blood of the dragon.',
user: 'daenerys',
date: new Date()
}, {
id: 5, // change this value to a string to see the bulk response with errors
text: 'A girl is Arya Stark of Winterfell. And I\'m going home.',
user: 'arya',
date: new Date()
}]
// The major part is below:
const body = dataset.flatMap(doc => [{ index: { _index: 'tweets' } }, doc])
const { body: bulkResponse } = await client.bulk({ refresh: true, body })
//
if (bulkResponse.errors) {
const erroredDocuments = []
// The items array has the same order of the dataset we just indexed.
// The presence of the `error` key indicates that the operation
// that we did for the document has failed.
bulkResponse.items.forEach((action, i) => {
const operation = Object.keys(action)[0]
if (action[operation].error) {
erroredDocuments.push({
// If the status is 429 it means that you can retry the document,
// otherwise it's very likely a mapping error, and you should
// fix the document before to try it again.
status: action[operation].status,
error: action[operation].error,
operation: body[i * 2],
document: body[i * 2 + 1]
})
}
})
console.log(erroredDocuments)
}
const { body: count } = await client.count({ index: 'tweets' })
console.log(count)
}
run().catch(console.log)
Reference link: https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/bulk_examples.html

how to merge response attributes of other table in node js

I have 3 Tables User, Cars and UserCars
User{id, name, phone, email}
Cars{id, name, manufacturer}
UserCars{id, car_id, user_id, role}
User have many cars(through UserCars)
Cars have many users(through UserCars)
I am using express js
router.get('/', async (req, res) => {
try {
let car = await Car.findOne({
where: {
id: req.car_id
}});
let users = await car.getUsers({joinTableAttributes: ['role']})
res.send(users)
} catch (e) {
console.log(e)
res.status(400).send(e)
}
})
and this my response
[
{
"id": 1,
"name": "test",
"email": null,
"phone": null,
"createdAt": "2019-07-09T09:38:11.859Z",
"updatedAt": "2019-07-12T04:34:20.922Z",
"User_car": {
"role": "driver"
}
}
]
but any idea how to include role in the user object, rather then specifying it separately in User_car table,
Is there a way where i can get the below output
[
{
"id": 1,
"name": "test",
"email": null,
"phone": null,
"role": 'driver'
"createdAt": "2019-07-09T09:38:11.859Z",
"updatedAt": "2019-07-12T04:34:20.922Z"
}
]
You can use sequelize.literal to get that field when getting your attributes.
attributtes: [
// define your other fields
[sequelize.literal('`users->User_car`.`role`'), 'role'],
]
Now, I not sure if that is going to work with car.getUsers. I usually do a single query with include and also define the "join" table so I can know how is name it on sequelize. Let me show you an example.
module.exports = (sequelize, DataTypes) => {
const UserCar = sequelize.define('UserCar', {
// id you don't need and id field because this is a N:M relation
role: {
type: DataTypes.STRING
},
carId: {
field: 'car_id',
type: DataTypes.INTEGER
},
userId: {
field: 'user_id',
type: DataTypes.INTEGER
},
}, {
tableName: 'User_car',
underscored: true,
createdAt: 'created_at',
updatedAt: 'updated_at',
});
UserCar.associate = (models) => {
models.user.belongsToMany(models.car, { as: 'cars', through: User_car, foreignKey: 'user_id' });
models.car.belongsToMany(models.user, { as: 'users', through: User_car, foreignKey: 'car_id' });
};
return UserCar;
};
router.get('/', async (req, res) => {
try {
const users = await User.findAll({
include: [{
model: Car,
as: 'cars',
where: { id: req.car_id }
}],
attributtes: [
'id',
'name',
'email',
'phone',
[sequelize.literal('`cars->User_car`.`role`'), 'role'],
]
})
res.send(users)
} catch (e) {
console.log(e)
res.status(400).send(e)
}
});

Resources