Finding all entries of an associated table in Sequelize Js - javascript

I am trying to find an array of entries from an associated table while querying from a main table.
Currently I am getting only one entry under the associated table when i try to query.
For example, I am getting an output as follows.
{
"id": 37,
"name": "Mr Tom",
"books": {
"id": 1278,
"name": "Book 1",
}
}
As you can see the books part comes as an object in an array. I am expecting it to be an array of books.
The following is the code I am using to query the data.
const authorId = req.params.id;
const AuthorDetails = await AUTHOR.findOne({
attributes: [
'id',
'name',
],
where: {
id: authorId,
},
include: [
{
model: BOOKS,
attributes: ['id','name'],
},
],
raw: true,
nest: true,
});
The relationship between the author and books is one to many. Where a
book can have only one author but an author can have many books.
This is defined as follows.
AUTHORS.hasMany(BOOKS);
BOOKS.belongsTo(AUTHORS);
edit: I noticed that when i remove the condition id:authorId it duplicates the author object and gives a unique book . For example
[
{
"id": 37,
"name": "Mr Tom",
"books": {
"id": 1278,
"name": "Book 1",
}
},
{
"id": 37,
"name": "Mr Tom",
"books": {
"id": 1279,
"name": "Book 2",
}
}
]

Related

Nesting sequelize.query results in a array of objects for INNER JOIN results

I'm trying to nest the results of a query with sequelize, I'm passing the raw query string in the sequelize.query function and organizing the results with the dotted notation with the option nest set to true. It is working and returning the results as intended, but it is not nesting the results in an array format, leaving the "root" object duplicated.
const result = await db.sequelize.query(s.toString(),
{
nest: true,
type: db.sequelize.QueryTypes.SELECT,
raw: true,
})
return result
This is the query generated by sequelize:
SELECT [UserCertifications].id AS [UserCertifications.id],[UserCertifications].campaign_id AS [UserCertifications.campaign_id],[UserCertifications].user_id AS [UserCertifications.user_id],[UserCertifications].certification AS [UserCertifications.certification],[Users].name AS [UserCertifications.Items.Users.name],[Items].title AS [UserCertifications.Items.title] FROM [UserCertifications] INNER JOIN [Items] ON (UserCertifications.item_id = Items.id) INNER JOIN [Users_Items] ON (Users_Items.item_id = Items.id) INNER JOIN [Users] ON (Users_Items.user_id = [Users].id) WHERE (campaign_id = 78)
It returns like this:
[
{
"UserCertifications": {
"id": 324,
"campaign_id": 78,
"user_id": 1,
"certification": null,
"Items": {
"Users": {
"name": "Admin"
},
"title": "Item 1"
}
}
},
{
"UserCertifications": {
"id": 324,
"campaign_id": 78,
"user_id": 1,
"certification": null,
"Items": {
"Users": {
"name": "Services"
},
"title": "Item 1"
}
}
},
{
"UserCertifications": {
"id": 324,
"campaign_id": 78,
"user_id": 1,
"certification": null,
"Items": {
"Users": {
"name": "Lucas"
},
"title": "Item 1"
}
}
},
{
"UserCertifications": {
"id": 324,
"campaign_id": 78,
"user_id": 1,
"certification": null,
"Items": {
"Users": {
"name": "Wally"
},
"title": "Item 1"
}
}
},
{
"UserCertifications": {
"id": 325,
"campaign_id": 78,
"user_id": 1,
"certification": null,
"Items": {
"Users": {
"name": "Admin"
},
"title": "Item 1"
}
}
},
...this is not the entire result, it is too big, but you can get the idea of what im alking about through this example.
The problem is, the result is correct, with "Items" and "Users" nested as intended, but i would like the result to be nested in a way that all the UserCertifications with "id: 324" are a single object with a single "Item" ("Item 1") and the users as an Array of users. Is there a way to nest the results like this using the dotted notation with Sequelize?
Aditional context: I'm passing the alias of the table names "Items" and "Users" like this to get that result, "UserCertifications.Items.title" and "UserCertifications.Items.Users.name", respectively
Disclaimer: It needs to be a raw query because I am building a query string from scratch using a "query builder", so i can't use the "Include" notation from sequelize.

How To Group For Multiple Fields In Sequelize

I need one help related to the sequelize and I am using postgres.
I want to group records in sequelize. Also the form and user value comes after populate or using include method of sequelize.
I have applied this code but it didn't work:-
{
group: ['formId', 'userId', 'responseFrom'],
include: [ { model: forms, as: 'form' }, { model: users, as: 'user' } ]
}
Here the name of table is formAnswers.
[{
"id": 21,
"formId": 1,
"userId": 123,
"formQuestionId": 2,
"answer": "8,5,6",
"responseFrom": "WAITING",
"createdAt": "2020-01-14T02:31:19.173Z",
"form": {
"id": 1,
"name": "Choose Group",
},
"user": {
"id": 123,
"fullName": "Test User",
"username": "test123",
}
},
{
"id": 22,
"formId": 1,
"userId": 123,
"formQuestionId": 1,
"answer": "3",
"responseFrom": "WAITING",
"createdAt": "2020-01-14T02:31:19.178Z",
"form": {
"id": 1,
"name": "Choose Group",
},
"user": {
"id": 123,
"fullName": "Test User",
"username": "test123",
}
}]
This is the sample record, there will be multiple records for each user.
I want to group the records by using formId and userId. Also you can consider responseFrom in group by. I have tried with group in sequelize but its not working.
I need only single record which have formId and userId same. If we are using the above data so the expected output will be:-
[{
"id": 22,
"formId": 1,
"userId": 123,
"formQuestionId": 1,
"responseFrom": "WAITING",
"createdAt": "2020-01-14T02:31:19.178Z",
"form": {
"id": 1,
"name": "Choose Group",
},
"user": {
"id": 123,
"fullName": "Test User",
"username": "test123",
}
}]
I need to apply pagination for this as well so please keep it in mind.
Possible solution: (not tested)
formAnswers.findAll({
attributes: [
sequelize.literal(`DISTINCT ON("form_question_responses"."formId","form_question_responses"."userId","form_question_responses"."responseFrom") 1`),
'id',
'formId',
'userId',
'responseFrom',
],
include: [
{ model: forms, as: 'form', attributes: ['id', 'name'] },
{ model: users, as: 'user', attributes: ['id', 'fullName', 'username'] }
],
// automatically order by as used DISTINCT ON - DISTINCT ON strictly orders based on columns provided
// order: [
// ['formId', 'ASC'],
// ['userId', 'ASC'],
// ],
offset: undefined, // for no offset
limit: 50,
})

Insert key's value in the array of object having same key

Say I've an array of object:
const Info = [{
"id": "1aa2",
"details": [{
"name": "rusty",
"age": "12",
"favourite": [ObjectId("602b696cb783fc15845d015e"), ObjectId("602b696cb783fc15845d0112")]
}]
},
{
"id": "3aa2",
"details": [{
"name": "john",
"age": "122",
"favourite": [ObjectId("602b696cb783fc15845d0112s"), ObjectId("602b696cb783fc15845d01wqs")]
}]
}
]
I want to merge favourite in one array as:
["favourite": [
ObjectId("602b696cb783fc15845d015e"),
ObjectId("602b696cb783fc15845d0112"),
ObjectId("602b696cb783fc15845d0112s"),
ObjectId("602b696cb783fc15845d01wqs")
]
]
I tried using for loop but it's creating nasty nested for loop which is reducing performance a lot.
Basically, you need to iterate through Info collection, iterate through 'details' sub-collection, and copy all data into a new array. After, just create a new structure using favs variable content or paste this code as object value directly.
BTW your result array need's to contain an object at least, like that:
[ { favourite: [...] } ]
About nested structures, you should try https://lodash.com/docs/4.17.15#flatMapDeep (at least just check the code)
const Info = [{
"id": "1aa2",
"details": [{
"name": "rusty",
"age": "12",
"favourite": ['ObjectId("602b696cb783fc15845d015e")', 'ObjectId("602b696cb783fc15845d0112")']
}]
},
{
"id": "3aa2",
"details": [{
"name": "john",
"age": "122",
"favourite": ['ObjectId("602b696cb783fc15845d0112s")', 'ObjectId("602b696cb783fc15845d01wqs")']
}]
}
]
const favs = Info.reduce((acc, item) => {
item.details.forEach(detail => {
acc.push(...detail.favourite);
})
return acc;
}, []);
console.log(favs);

Get minimum column value from related entity

Please, help me. I cant find information about how do this.
I have got this code. It load all products with all relations. One of relations is product item. In product item entity I have got price column.
How I can get minimal product item price without get in my response array of product items?
const { skip, take } = pagination;
const query = this.createQueryBuilder('product');
query.where('product.shop = :id AND product.blocked = FALSE', {
id: shop.id,
});
if (skip) {
query.offset(Number(skip));
}
if (take) {
query.limit(Number(take));
}
query.leftJoin('product.info', 'info');
query.leftJoin('product.avatar', 'avatar');
// load product items
query.leftJoin('product.productItem', 'item');
query.select([
'product.id',
'product.path',
'info.name',
'info.description',
'info.info',
'info.lang',
'avatar.path',
'avatar.type',
'item.price'
]);
const [list, amount] = await query.getManyAndCount();
Now i have got:
{
"list": [
{
"id": 3,
"path": "admin-product-2",
"order": 1,
"shop": {
"id": 1
},
"info": [
{
"name": "Admin Name ;)",
"description": "Shorty",
"info": "",
"lang": "RU"
}
],
"avatar": null,
"productItem": [
{
"price": 1000
},
{
"price": 500
},
{
"price": 300
},
{
"price": 2000
},
{
"price": 3000
}
]
}
]
}
........
But I need:
{
"list": [
{
"id": 3,
"path": "admin-product-2",
"order": 1,
"shop": {
"id": 1
},
"info": [
{
"name": "Admin Name ;)",
"description": "Shorty",
"info": "",
"lang": "RU"
}
],
"avatar": null,
"minProductItemPrice": 300
}
]
}
Pls help me
You can find the answer for this on Stackoverflow already.
Here is a similar question Typeorm select max with specific column
Basically, getManyAndCount() method that you are using is useful when fetching entities. In your case, you are trying to obtain an aggregate value encompassing multiple entities.
You need to make separate selection, like so
query.select("MIN(item.price)", "min");
and then get the result with
return query.getRawOne();

How to show a nested object as a super object in MongoDB?

As it is stated here, I had to save reference objects inside of a nested key called 'item';
var userSchema = new Schema({
name: String,
connections: [{
kind: String,
item: { type: ObjectId, refPath: 'connections.kind' }
}]
});
var organizationSchema = new Schema({ name: String, kind: String });
var User = mongoose.model('User', userSchema);
var Organization = mongoose.model('Organization', organizationSchema);
In my DB, it is more like this:
var childSchema = new Schema({
kind: String,
item: {
type: Schema.Types.ObjectId,
refPath: 'children.kind'
}
},{ _id : false, strict:false });
var schema = new Schema({
name: String,
kind: String,
children: [childSchema]
},{
strict: false
});
Now, it is a tree based folder structure model, and it can have either a Folder or a Leaf as child object.
I needed a recursive populate, so I find an answer on SO, it became like this;
var autoPopulateChildren = function(next) {
this.populate({path:'children.item', select:'name id children'});
next();
};
schema.pre('findOne', autoPopulateChildren)
.pre('find', autoPopulateChildren)
Now, when I make a find query, I get this-like example;
{
"name": "Some Folder",
"children": [
{
"kind": "Leaf",
"item": {
"name": "First Level Leaf",
"id": "5b61c85f25375fddf6048d3c"
}
},
{
"kind": "Folder",
"item": {
"name": "First Level Folder",
"id": "5b61d844d77fb30b9537e5d1"
"children": [
{
"kind": "Leaf",
"item": {
"name": "Second Level Leaf",
"id": "5b61c85f25375fddf6048d3c"
}
}
]
}
}
],
"id": "5b61c85f25375fddf6048d3d"
}
But now, I need to get rid of 'kind' (don't show) and also I need to show 'item' object as a child (it should be name instead of item:{name:'a'}:
{
"name": "Some Folder",
"children": [
{
"name": "First Level Leaf",
"id": "5b61c85f25375fddf6048d3c"
},
{
"name": "First Level Folder",
"id": "5b61d844d77fb30b9537e5d1"
"children": [
{
"name": "Second Level Leaf",
"id": "5b61c85f25375fddf6048d3c"
}
]
}
],
"id": "5b61c85f25375fddf6048d3d"
}
How can I do this on autoPopulateChildren function?

Categories

Resources