Typeorm relations query builder - node.js

I have a little problem figuring out how to get data from a linked table using queryBuilder
Currently i have this code:
const users = await databaseConntection
.getRepository(User)
.createQueryBuilder("user")
.select(["images.author_id", "user.id", "user.username"])
.leftJoinAndSelect(
(queryBuilder) =>
queryBuilder
.select(["title", "updated_at", "author_id"])
.from(Image, "image")
.orderBy({ updated_at: "ASC" })
.take(5),
"images",
"images.author_id = user.id"
)
.andWhere("username LIKE :profile")
.setParameters({
profile: `%${profile}%`,
})
.groupBy("images.author_id")
.take(limit)
.skip(page * limit - limit)
.getRawMany();
Current result:
column "user.id" must appear in the GROUP BY clause or be used in an aggregate function
Expected result:
[
{
"id": 1,
"username": "some username",
"images": [
{
"title": "some image title",
"updated_at": "2021-05-21T03:49:44.299Z",
"author_id": 1
}
...rest 4 images
]
}
...rest users
]
How i can achieve this result using query builder?
Thanks for any helping.

I don't know what is wrong with my code, but i was migrate to prisma orm, and he work like as expected.
Here the code using prisma orm, and this return the expected result (without ids):
const users = await prisma.user.findMany({
where: {
username: {
contains: profile as string,
},
},
select: {
username: true,
images: {
select: {
title: true,
updated_at: true,
},
orderBy: {
updated_at: "asc",
},
take: 5,
},
},
take: limit,
skip: page * limit - limit,
});

Related

How to query and filtering with multiple elements in typeorm - nest js

What is the best way to query and filtering relation entity / many to many field in typeorm. For example in my case i have books with 2 categories:
action & adventure.
Then i want filtering by that categories.
so the url e.g:
..../books?categories='action,adventure'.
My problem i can only filter with only 1 or i must use orWhere in my querybuilder but if i add the categories to
'action,adventure,scifi'
is still got the result not filtering of all of them categories
book.entity.ts
#Entity()
export class Book {
#PrimaryGeneratedColumn()
id: number;
#Column()
title: string;
#Column()
description: string;
#Column()
thumbnail: string;
#ManyToMany(() => BooksCategory, {
cascade: true,
})
#JoinTable()
category: BooksCategory[];
#Column({
nullable: false,
default: () => 'CURRENT_TIMESTAMP',
type: 'timestamp',
})
created_at: Date;
#Column({
nullable: false,
default: () => 'CURRENT_TIMESTAMP',
type: 'timestamp',
})
updated_at: Date;
}
Here my service function
books.service.ts
async findAll(query: GetBooksQueryDto): Promise<Book[]> {
const booksQuery = await this.booksRepository.createQueryBuilder('book');
const joins = await booksQuery.leftJoinAndSelect(
'book.category',
'category',
);
const titleFilter = await joins.andWhere('book.title LIKE :title', {
title: `%${query.title}%`,
});
const categoryFilter = titleFilter
.andWhere('category.name LIKE :category', {
category: `action`,
})
.andWhere('category.name LIKE :category', {
category: `adventure`,
});
return await categoryFilter.getMany();
}
got return like this
[
{
"id": 1,
"title": "Love is war",
"description": "One piece is real",
"thumbnail": "file://",
"created_at": "2022-11-20T16:36:11.000Z",
"updated_at": "2022-11-20T16:36:11.000Z",
"category": [
{
"id": 2,
"name": "adventure"
}
]
}
]
My expection is like this
[
{
"id": 1,
"title": "Love is war",
"description": "One piece is real",
"thumbnail": "file://",
"created_at": "2022-11-20T16:36:11.000Z",
"updated_at": "2022-11-20T16:36:11.000Z",
"category": [
{
"id": 1,
"name": "action"
},
{
"id": 2,
"name": "adventure"
}
]
}
]
the problem the second argument or the next argument of andWhere() in categoryFilter is overwriting the previous value of categories array.
Im not sure why are you using filtering in this way.
You should be using better naming convention for variables. You dont need all those variables because if dont have any conditions.
Based on your code above i would write something like this.
return this.booksRepository.createQueryBuilder('book').leftJoinAndSelect(
'book.category',
'category',
).where('book.title LIKE :title', {
title: `%${query.title}%`,
}).andWhere('category.name IN (:...categories)', {
categories: query.categories,
}).getMany();
You could even can use Typerorm find method for this query.

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.

mongoose find object into array of object

I'm new in mongoose and I'm trying to find user by code [user.test.test1.code] , any idea ?
Model :
const userSechema = new mongoose.Schema({
name: {
type: String,
required: true
},
test: [{}],
})
Data :
{
"_id": {
"$oid": "600020ab34742c2d34ae45e5"
},
"test": [{
"test1": {
"code": 11111
},
"test2": {
"code": 22222
}
}]
"name": "daniel"
}
query :
let regex = new RegExp(req.query.searchUserKey, 'i')
const users = await User.find({ $or: [{'name': regex },{'test.test1': { code : regex} }]})
-- Solution --
Thanks you guys, both answers is work for me
Is as simple as do "test.test1.code": 418816 into find query like this:
db.collection.find({
"test.test1.code": 418816
})
This query will give you all documents where exists test.test1.code with value 418816.
Note that this query return the whole document, not only the sub-document into the array. But I'm assuming by your post that a user is the document where exists the field name.
Example here
you can use $elemMatch, check the documentation
const users = await User.find(
{ test: { $elemMatch: { "test1.code": 418816 } } }
)

Sequelize ORM return a weird response after inner join tables in nodejs

I use sequelize orm to manage my data base (mysql).
I make a inner join that work good but the problem that the table that join return a weird variable.
this is my code
const getReports = id => {
return new Promise((resolve, reject) => {
models.Report.findAll({
where: { companyID: [513603324, 515490704, 511493827] },
include: [{
model: models.Reports_type,
attributes:["name"],
required: true
}],
raw: true
})
.then(result => {
resolve(result);
})
.catch(err => {
reject(err);
});
});
};
The output is
[
{
"id": 8,
"creatorUserID": 1,
"currentUserEditorID": 1,
"companyID": 511493827,
"stageID": 1,
"scenarioID": 1,
"typeID": 1,
"year": 2020,
"deadLine": "2019-10-30T22:00:00.000Z",
"createdAt": "2019-10-29T08:31:19.000Z",
"updatedAt": "2019-10-29T08:31:19.000Z",
"Reports_type.name": "excelent",
"companyName": "energy",
}
]
The problem is i get it weird like this:
"Reports_type.name"
I want the output be:
"name"
This topic has been covered before - see this.
To avoid the prefix, attributes must be specified in the main model rather than the included model. The example below should produce all fields in Report plus Reports_type.name. Note: the alias of Reports_type may be a little different than I've guessed - if you get a "field does not exist", find the correct alias from the generated SQL.
models.Report.findAll({
where: { companyID: [513603324, 515490704, 511493827] },
include: [{
model: models.Reports_type,
attributes:[], // suppress here
required: true
}],
raw: true,
attributes: {
include: [[Sequelize.col("reports_types.name"), "name"]] // include here; table alias may be a little different!
}
})

Export To Excel filtered data with Free jqgrid 4.15.4 in MVC

I have a question regarding Export to Excel in free-jqgrid 4.15.4. I want to know how to use this resultset {"groupOp":"AND","rules":[{"field":"FirstName","op":"eq","data":"Amit"}]} into my Business Logic Method.
Just for more clarification, I've using OfficeOpenXml and if I don't use filtered resultset(aforementioned) it is working fine and I'm able to download file with full records in an excel sheet. But I'm not sure what to do or how to utilize the resultset {"groupOp":"AND","rules":[{"field":"FirstName","op":"eq","data":"Amit"}]}
If required I can share my controller and BL code.
I have added a fiddle which shows implementation of Export to Excel button in jqGrid pager.
Before coming to here, I've read and tried to understand from following questions:
1] jqgrid, export to excel (with current filter post data) in an asp.net-mvc site
2] Export jqgrid filtered data as excel or CSV
Here is the code :
$(function () {
"use strict";
var mydata = [
{ id: "10", FirstName: "test", LastName: "TNT", Gender: "Male" },
{ id: "11", FirstName: "test2", LastName: "ADXC", Gender: "Male" },
{ id: "12", FirstName: "test3", LastName: "SDR", Gender: "Female" },
{ id: "13", FirstName: "test4", LastName: "234", Gender: "Male" },
{ id: "14", FirstName: "test5", LastName: "DAS", Gender: "Male" },
];
$("#list").jqGrid({
data: mydata,
colNames: ['Id', 'First Name', 'Last Name', 'Gender'],
colModel: [
{
label: "Id",
name: 'Id',
hidden: true,
search: false,
},
{
label: "FirstName",
name: 'FirstName',
searchoptions: {
searchOperators: true,
sopt: ['eq', 'ne', 'lt', 'le','ni', 'ew', 'en', 'cn', 'nc'],
}, search: true,
},
{
label: "LastName",
name: 'LastName',
searchoptions: {
searchOperators: true,
sopt: ['eq', 'ne', 'lt', 'ni', 'ew', 'en', 'cn', 'nc'],
}, search: true,
},
{
label: "Gender",
name: 'Gender',
search: true, edittype: 'select', editoptions: { value: 'Male:Male;Female:Female' }, stype: 'select',
},
],
onSelectRow: function (id) {
if (id && id !== lastsel) {
jQuery('#list').restoreRow(lastsel);
jQuery('#list').editRow(id, true);
lastsel = id;
}
},
loadComplete: function (id) {
if ($('#list').getGridParam('records') === 0) {
//$('#grid tbody').html("<div style='padding:6px;background:#D8D8D8;'>No records found</div>");
}
else {
var lastsel = 0;
if (id && id !== lastsel) {
jQuery('#list').restoreRow(lastsel);
jQuery('#list').editRow(id, true);
lastsel = id;
}
}
},
loadonce: true,
viewrecords: true,
gridview: true,
width: 'auto',
height: '150px',
emptyrecords: "No records to display",
iconSet:'fontAwesome',
pager: true,
jsonReader:
{
root: "rows",
page: "page",
total: "total",
records: "records",
repeatitems: false,
Id: "Id"
},
});
jQuery("#list").jqGrid("navButtonAdd", {
caption: "",
buttonicon: "fa-table",
title: "Export To Excel",
onClickButton: function (e) {
var projectId = null;
var isFilterAreUsed = $('#grid').jqGrid('getGridParam', 'search'),
filters = $('#grid').jqGrid('getGridParam', 'postData').filters;
var Urls = "/UsersView/ExportToExcel_xlsxFormat?filters="+ encodeURIComponent(filters); //' + encodeURIComponent(filters);/
if (totalRecordsCount > 0) {
$.ajax({
url: Urls,
type: "POST",
//contentType: "application/json; charset=utf-8",
data: { "searchcriteria": filters, "projectId": projectId, "PageName": "MajorsView" },
//datatype: "json",
success: function (data) {
if (true) {
window.location = '/UsersView/SentFiletoClientMachine?file=' + data.filename;
}
else {
$("#resultDiv").html(data.errorMessage);
$("#resultDiv").addClass("text-danger");
}
},
error: function (ex) {
common.handleAjaxError(ex.status);
}
});
}
else {
bootbox.alert("There are no rows to export in the Participant List")
if (dialog) {
dialog.modal('hide');
}
}
}
});
});
https://jsfiddle.net/ap43xecs/10/
There are exist many option to solve the problem. The simplest one consist of sending ids of filtered rows to the server instead of sending filters parameter. Free jqGrid supports lastSelectedData parameter and thus you can use $('#grid').jqGrid('getGridParam', 'lastSelectedData') to get the array with items sorted and filtered corresponds to the current filter and sorting criteria. Every item of the returned array should contain Id property (or id property) which you can use on the server side to filter the data before exporting.
The second option would be to implement server side filtering based on the filters parameter, which you send currently to the server. The old answer (see FilterObjectSet) provides an example of filtering in case of usage Entity Framework. By the way, the answer and another one contain code, which I used for exporting grid data to Excel using Open XML SDK. You can compare it with your existing code.
In some situations it could be interesting to export grid data to Excel without writing any server code. The corresponding demo could be found in the issue and UPDATED part of the answer.

Resources