How to return only some columns of a relations with Typeorm - postgresql

Ok, i'm having trouble with getting the relations with typeorm, when i run the service it returns me all the data from the relation, and i want only specific fields, like id and name.
Here's my code:
async findById(id: string): Promise<UsersUseOfferHistoric> {
return await this.repository.findOne({
where: { id },
relations: ['userId', 'offerId'],
});
}
Here's the json Output:
{
"id": "da0fd04e-17c6-4412-b342-a4361d191468",
"createdAt": "2020-01-07T19:48:30.840Z",
"userId": {
"id": "bdc00227-569f-44b5-9bdd-c8de03661ebd",
"name": "Alexandre Vieira",
"cpf": "10443771430",
"email": "av.souza2018#gmail.com",
"password": "asjdsifjdsfasf",
"imagePath": "/me.png",
"active": true,
"lastLogin": "2020-01-07T19:40:26.850Z",
"createdAt": "2020-01-07T19:40:26.850Z",
"updatedAt": "2020-01-07T19:40:26.850Z"
},
"offerId": {
"id": "e399560c-d2c2-4f4e-b2b1-94cae3af3779",
"offerDrescription": "Nova oferta top",
"discountCoupon": " Desconto top",
"discountValidity": "2020-01-07T14:18:19.803Z",
"discountPercentage": 20,
"discountQuantityLimit": 50,
"createdAt": "2020-01-07T19:45:33.589Z",
"updatedAt": "2020-01-07T19:45:33.589Z"
}
}
Here's the output i want:
{
"id": "da0fd04e-17c6-4412-b342-a4361d191468",
"createdAt": "2020-01-07T19:48:30.840Z",
"userId": {
"id": "bdc00227-569f-44b5-9bdd-c8de03661ebd",
"name": "Alexandre Vieira",
},
"offerId": {
"id": "e399560c-d2c2-4f4e-b2b1-94cae3af3779",
"offerDrescription": "Nova oferta top",
}
}

The findOne function accepts an select: ['id', 'createdAt'] property where you can filter the fields of the outgoing relation. To explicitly select the returned fields of a joined table (using the relations property does implicitly a left join) you have to use a query builder.
await getRepository(Foo).createQueryBuilder('foo')
.where({ id: 1})
.select(['foo.id', 'foo.createdAt', 'bar.id', 'bar.name'])
.leftJoin('foo.bars', 'bar') // bar is the joined table
.getMany();

Try something like that:
...findOne({
select: {
id: true,
createdAt: true,
userId: {
id: true,
name: true,
},
offerId: {
id: true,
offerDrescription: true,
},
},
...
where: {...},
})

You can do it like this if you rather use the repository API instead of the queryBuilder
return await this.repository.findOne({
where: { id },
select: {
userId: {
id: true,
name: true
},
offerId: {
id: true,
offerDrescription: true
}
},
relations: {
userId: true,
offerId: true,
}
});

Related

How to create in mongoose, if it exists, update it in mongoose

I have problem when I want create new model or if not exist, update it.
For example, I have data in a database:
{
"unix": 1668380400,
"type": "soup",
"order": 1,
"value": "Chicken"
},
{
"unix": 1668380400,
"type": "main",
"order": 0,
"value": "Gulash"
},
{
"unix": 1668553200,
"type": "soup",
"order": 0,
"value": "Asian"
}
}
I want to get to the point that when unix and type and order are the same - modify the value. But if the element with the same unix, order and type is not found in the database - add a completely new record to the db.
I thought this was how I would achieve the desired state. But a mistake.
router.post("/add", async (req, res) => {
const data = req.body;
await data.map((el) => {
const { unix, type, order, value } = el;
Menu.findOneAndUpdate(
{ unix, type, order },
{ unix, type, order, value },
{ new: true, upsert: true }
);
});
res.status(201).json({ status: true });
});
req.body:
[
{
"unix": 1668380400,
"type": "main",
"order": 2,
"value": "Sushi"
},
{
"unix": 1668553200,
"type": "soup",
"order": 0,
"value": "Thai"
}
]
Thanks for any help.
I think I found a solution. Everything works as it should, but wouldn't it be better to send the data with JSON.stringify() and then parse this data on the servers using JSON.parse()?
Another thing is the map method. Is it OK like this? Can't cause throttling?
router.post("/add", (req, res) => {
const data = req.body;
data.map(async (el) => {
const { unix, type, order, value } = el;
await Menu.findOneAndUpdate(
{ unix, type, order },
{ value },
{ upsert: true }
);
});
res.status(201).json({ status: true });
});

Sequelize nested include without null properties

using ExpressJs/Postgres/Sequelize and when doing findOne I am getting an object return that contains nested objects with following data in the response:
"CompanyVolume": null,
"CompanyMarkets": [],
Is there a way to avoid receiving these properties with null/[] from Postgres?
Appreciate any thoughts...:)
const kyc = await db.Kyc.findOne({
where: {id: req.params.id},
include: [
{model: db.Company,
include: [
{ model: db.CompanyStakeholder, through: db.Role },
{ model: db.CompanyDelivery,
// where: {
// deliveryAverageDurationAmount: {[Op.not]:null},
// }
//returns Cannot read properties of undefined (reading 'not')
},
{ model: db.CompanyVolume },
{ model: db.CompanyDelivery },
{ model: db.CompanyMarket },
],
nest: true,
})
the response object with properties including null or empty arrays
[
{
"id": 5,
"kycTitle": "KYC1006428",
"kycPasscode": null,
"kycDescription": "The best kyc ever, lorem epsum sanctus vita loca",
"kycStartDate": "2022-01-28",
"kycStatus": null,
"kycConsent": "approved",
"kycConsentDate": "2022-01-27T14:01:39.924Z",
"createdAt": "2022-01-27T13:19:41.649Z",
"updatedAt": "2022-01-27T14:01:39.919Z",
"id_User": 1,
"Company": {
"id": 6,
"companyName": "Niky",
"companyEntityType": null,
"companyVatNumber": "",
"companyRegistrationNumber": "",
"companyPubliclyListed": null,
"companyAddress1": "Pepovej 234",
"companyAddress2": "",
"companyCity": "Dada",
"companyPostCode": "3400",
"companyCountry": "Owner",
"companyPhone": "+21321321231",
"createdAt": "2022-01-27T13:19:41.669Z",
"updatedAt": "2022-01-27T13:19:41.676Z",
"KycId": 5,
"CompanyStakeholders": [], //I don't want this returned
"CompanyDelivery": null, //I don't want this returned
"CompanyVolume": null, //I don't want this returned
"CompanyMarkets": [], //I don't want this returned
},
}
]
The different Associations:
Company.associate = function (models) {
Company.hasOne(models.Contact)
Company.hasOne(models.CompanyDelivery)
Company.hasMany(models.CompanyMarket)
Company.hasMany(models.CompanyPosBilling)
Company.hasMany(models.CompanySettlement)
Company.hasOne(models.CompanySubscription)
Company.hasOne(models.CompanyVolume)
Company.hasMany(models.CompanyWebsite)
Company.belongsTo(models.Kyc)
Company.belongsToMany(models.CompanyStakeholder, {
through: models.Role,
unique: false
})
}
CompanyDelivery.associate = function (models) {
CompanyDelivery.belongsTo(models.Company)
}
CompanyMarket.associate = function (models) {
CompanyMarket.belongsTo(models.Company)
}
Kyc.associate = function (models) {
Kyc.hasOne(models.Company)
}
CompanyStakeholder.associate = function (models) {
CompanyStakeholder.belongsToMany(models.Company, {
through: models.Role,
unique: false
})
}

Mongoose nested object not updating 'cannot create field "foo" in element'

I have a similar issue to this question.
I'm trying to create a new field using "findAndUpdate". I've tried all the methods, $set, $push, $addSet... none of them seem to be working and I keep getting the same error.
Here's the code:
router.post('/accept', auth, async (req, res) => {
const useremail = user.email
const originalEvent = await Event.findOneAndUpdate({eventId: 61469041, isOrganizer: true, "attendees.email": useremail},
{"$push":{"attendees.status" : "accepted"}},
{new: true})
res.status(200).json({originalEvent, event})
}
catch (e) {
res.status(400).json({ msg: e.message, success: false });
}
});
Here's the error code:
"Cannot create field 'status' in element {attendees: [ { _id: ObjectId('5f80a02a82dceb2810e0aa66'), email: "bob#gmail.com", name: "Bob" } ]}"
Here's the object I'm trying to update:
{
"organizer": {
"email": "alex#gmail.com",
"name": "Alex"
},
"_id": "5f80a02a82dceb2810e0aa65",
"title": "Go to the beach",
"eventId": 61469041,
"isOrganizer": true,
"user": "5f05f23417ca6ab69ccc4cf2",
"attendees": [
{
"_id": "5f80a02a82dceb2810e0aa66",
"email": "bob#gmail.com",
"name": "Bob"
}
],
"__v": 0,
}
Expected outcome:
{
"organizer": {
"email": "alex#gmail.com",
"name": "Alex"
},
"_id": "5f80a02a82dceb2810e0aa65",
"title": "Go to the beach",
"eventId": 61469041,
"isOrganizer": true,
"user": "5f05f23417ca6ab69ccc4cf2",
"attendees": [
{
"_id": "5f80a02a82dceb2810e0aa66",
"email": "bob#gmail.com",
"name": "Bob",
"status": "accepted"
}
],
"__v": 0,
}
SOLVED with this:
const originalEvent = await Event.findOneAndUpdate({eventId: eventId, "isOrganizer": true,
"attendees": {$elemMatch: {email: useremail}}
},
{ $set: { "attendees.$.status": "accepted"} }
)
res.status(200).json(originalEvent)
}
Referencing attendees.status doesn't make sense because in your schema attendees is not an object (with fields such as status) but an array. But you can do it differently. If you have the index of the attendee you want to mutate, you can do { $set: { "attendees.0.status": "accepted" } }, where 0 is the index in the array.
Also, with regards to the first half of your question, the error you're seeing is because $push works on arrays. So in order for your operation to work, you'd have to first initialize such an object {attendees: { status: [] } }.
If the field is not an array, the operation will fail. (docs)

How to multiply NumberDecimal values in mongodb

I have the following structure:
{
"_id": "5d0118f0f57a282f89bc5f71",
"product": {
"_id": "5cfed37375a13067dd01ddb7",
"name": "My product",
"description": "My description",
"purchased_amount": 15,
"unit_price_mex": "45",
"unit_price_to_sell": "5",
"travel": "5cf58713d6f7f1657e2d8302",
"__v": 0,
"id": "5cfed37375a13067dd01ddb7"
},
"client": {
"_id": "5cf1778efffb651fad89d8b6",
"name": "Client name",
"description": "",
"__v": 0
},
"purchased_amount": 3,
"fch": "13/6/2019",
"__v": 0
},
{
"_id": "5d0151afda1a446008f1817b",
"product": {
"_id": "5cfed1995eaf2665c45efd82",
"name": "Camisa",
"description": "Camisas buenas",
"purchased_amount": 10,
"unit_price_mex": "100",
"unit_price_to_sell": "15",
"travel": "5cf56b04462a865264fabb9d",
"__v": 0,
"id": "5cfed1995eaf2665c45efd82"
},
"client": {
"_id": "5cf1778efffb651fad89d8b6",
"name": "Randy",
"description": "El que trabaja aqui",
"__v": 0
},
"purchased_amount": 34,
"fch": "12/6/2019",
"__v": 0
},
Where client and product are of type ObjectId. This is the Schema:
Client Model
var mongoose = require('mongoose');
const mongoosePaginate = require('mongoose-paginate-v2');
var clientSchema = new mongoose.Schema({
name: String,
description: String
}).plugin(mongoosePaginate);
var Client = mongoose.model('Client', clientSchema);
module.exports = Client;
Product Model
var mongoose = require('mongoose');
const mongoosePaginate = require('mongoose-paginate-v2');
var productSchema = new mongoose.Schema({
name: String,
description: String,
purchased_amount: Number,
unit_price_mex: mongoose.Schema.Types.Decimal128,
unit_price_to_sell: mongoose.Schema.Types.Decimal128,
travel: { type: mongoose.Schema.Types.ObjectId, ref: 'Travel' }
}).plugin(mongoosePaginate);
productSchema.set('toJSON', {
getters: true,
transform: (doc, ret) => {
if (ret.unit_price_mex) {
ret.unit_price_mex = ret.unit_price_mex.toString();
}
if ( ret.unit_price_to_sell ) {
ret.unit_price_to_sell = ret.unit_price_to_sell.toString();
}
}
})
var Product = mongoose.model('Product', productSchema);
module.exports = Product;
I need to get the multiplication sum of purchased_amount by product.unit_price_to_sell. My code is the following but always returns 0. Apparently, "$product.unit_price_to_sell" does not return the decimal value.
var aggregate = InvoiceModel.aggregate([
{ $match: { client: mongoose.Types.ObjectId( id ) } },
{ $group: { _id: null, total: { $sum: { $multiply: [ "$purchased_amount", "$product.unit_price_to_sell" ] } } } }
]);
InvoiceModel.aggregatePaginate(aggregate, {}, (error, aggs) => {
InvoiceModel.paginate({ client: id },{ page, limit, populate: 'client product' }, (err, value) => {
return res.status(200).send({
results: value.docs,
totalPages: value.totalPages,
totalDocs: value.totalDocs,
purchase_amount_total : aggs.docs[0].total
})
})
})
MongoDB cannot use string values in arithmetic expressions. You must either store the values using their numeric non-string representations, or you must use an aggregation operator like $toDecimal to convert the values to their numeric representations first.
Modifying your $group stage to something like the following should work:
{ $group: { _id: null, total: { $sum: { $multiply: [ "$purchased_amount", { $toDecimal: "$product.unit_price_to_sell" } ] } } }
Please note, however, that this will only work for MongoDB versions >= 4.0. If you're using an older version of MongoDB, you will either need to upgrade it to at least version 4.0 or begin converting your existing values from strings to numbers.

Mongoose $push add to document

I'm trying to add an element to an existing array, but it produces an error:
The field 'data' must be an array but is of type object in document
Scheme:
const testScheme = new Schema({
user: {
type: String,
required: true
},
data: [{
platform: {
type: String,
required: true
},
item_name: {
type: String,
required: true
},
price: {
type: Number,
default: 0
},
updatedAt: Date
}]
}, {
versionKey: false,
timestamps: true
});
Document in mongodb:
"data": [{
"price": 50,
"_id": "5a84268d6c78a60c10479437",
"platform": "pl1",
"item_name": "test"
}],
"_id": "5a841bccb44cb8cd5b974d71",
"user": "Ivan",
"updatedAt": "2018-02-14T12:07:41.793Z",
"createdAt": "2018-02-14T11:21:48.104Z"
Query:
var item = {
"platform": "pl700",
"item_name": "someText",
"price": 700,
"updatedAt": new Date()
};
Data.findOneAndUpdate({
'user': 'Ivan'
}, {
$push: {
'data': item
}
}, {
safe: true,
upsert: true
},
function(err, data) {
if (err) return res.status(500).send({
'error': err
});
res.status(200).send({
'data': data
});
}
);
I trying query with $set parametr and it works, but $push, $addToSet didn't work for me. Also i tried to google this problem and can't solve it.
It is not clear what you are intending to do.
To push an item into array you use $addToSet/$push. For updating a array you use $set.
Using $set you can update the whole document or you can update the specific field.
Update whole doc
Data.findOneAndUpdate({
'user': 'Ivan',
'data._id':item._id
}, {
$set: {
'data.$': item
}
}...
)
Update specific field
Data.findOneAndUpdate({
'user': 'Ivan',
'data._id':item._id
}, {
$set: {
'data.$.price': item.price
}
}...
)