Filter related models by Sequelize - javascript

I have two models in my aplication, Delivery and DeliveryProblem.
DeliveryProblem has a PK (delivery_id) from Delivery:
static associate(models) {
this.belongsTo(models.Delivery, {
foreignKey: 'delivery_id',
as: 'delivery',
});
}
I need select all Deliveries that have a Delivery Problem.
In my Controller, a have the follow method:
async index(req, res) {
const response = await DeliveryProblem.findAll({
order: ['id'],
attributes: ['delivery_id'],
});
// Filter all Deliveries with problem
const ids = [...new Set(response.map((x) => x.delivery_id))];
const deliveries = Delivery.findAll({
where: , // <<< How can I filter ?
order: ['id'],
});
return res.json(deliveries);
}

const Sequelize = require('sequelize')
const Op = Sequelize.Op
...
// Filter all Deliveries with problem
const ids = [...new Set(response.map((x) => x.delivery_id))];
const deliveries = Delivery.findAll({
where: {
id: {
[Op.in]: ids
}
},
order: ['id'],
});

Related

Prisma find many and count in one request

I have a pagination in my category service, and I have to return obj with total count of categories and data
But there's can be some parameters. As example, I should return categories that was created by certain user:
async findAll(
{ onlyParents }: ParamsCategoryDto,
user: ITokenPayload | undefined,
): Promise<IFilterRes> {
const categories = await this.prisma.category.findMany({
where: {
user_id: user?.id,
},
});
return {
pagination: {
total: this.prisma.category.count({
where: { // <- duplicate
user_id: user?.id,
},
}),
},
data: categories,
};
}
I should duplicate where in both query. Which is not very nice. Is there any option to do it in one request.
P.S. I can make some var for where, but in this way I lose typification, which I also don't like.
This is my example code to acheive it with a single transaction, no duplicate code and not losing type autocomplete
import { Prisma } from '#prisma/client';
import { PrismaClient } from '#prisma/client'
const prisma = new PrismaClient()
const findAll = async (userId: String) => {
const query: Prisma.categoriesFindManyArgs = {
where: {
user_id: userId,
}
};
const [categories, count] = prisma.$transaction([
prisma.categories.findMany(query),
prisma.categories.count({ where: query.where })
]);
return {
pagination: {
total: count
},
data: categories
};
};

Insert data into MongoDb using mongoose

I have an array of strings, I want to map through this array and update my collection with it's values.
This is What I have tried:
if (employees) {
employees.map((employee) => {
Employee.updateOne({ $push: { name: employee.name } })
.then((data) => {
console.log(data);
})
.catch((e) => {
console.log(e);
});
});
}
At the top I am importing my model :
const Employee = require('../../models/employees');
My Model looks like this :
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const EmployeeSchema = new Schema({
name: { type: String },
});
const Employee = mongoose.model('employee', EmployeeSchema);
module.exports = Employee;
My console is logging the next :
{ n: 0, nModified: 0, ok: 1 }
But when i check the database the data is not there and no collection is created.
updateOne has following syntax.
First parameter is condition/filter.
Second parameter is doc to be updated.
Third is options. Where you need to pass upsert to true.
Note: If upsert is set to true then updateOne will create new doc if the filter results empty.
const insertEmployees = () => {
try {
if (employees) {
employees.map(async employee => {
let filter = { name: employee.name }
let doc = { $push: { name: employee.name } }
let options = { upsert: true }
await Employee.updateOne(filter, doc, options)
});
}
} catch (error) {
console.log(error);
}
}

Mongoose find by a subdocument's value

I have 2 schemas
const schema = Schema({
headLine: {
type: String,
required: false
},
availableDays: [{
type: Schema.Types.ObjectId,
ref: AvailableDay
}]
}, {collection: 'providers', timestamps: true});
module.exports = mongoose.model("Provider", schema);
const schema = Schema({
day: {
type: String,
enum: ['Mondays','Tuesdays','Wednesdays','Thursdays','Fridays','Saturdays','Sundays']
},
timeFrom: String,
timeTo: String
}, {collection: 'availableDays', timestamps: true});
module.exports = mongoose.model("AvailableDay", schema);
Then in a route I call to a repository like this
router.get('/', async (req, res) => {
const match = {};
const sort = {};
const options = {};
// Arrange sort
if(req.query.sortBy){
const sortArray = JSON.parse(req.query.sortBy);
sortArray.map(e => sort[e[0]] = e[1] && e[1] === 'desc' ? -1 : 1);
options['sort'] = sort
}
// Get the pagination: limit how many, skip where it starts
if(req.query.limit) {
options['limit'] = parseInt(req.query.limit);
}
if(req.query.skip) {
options['skip'] = parseInt(req.query.skip);
}
const docs = await ProviderRepository.findBy(match, {}, options);
res.status(200).json(docs)
});
So what I need here is to filter providers for an AvailableDay monday and return the docs and count the total docs for pagination. I'm doing something like this without success
const findBy = async (params, projection = "", options = {}, callback) => {
const data = () => {
Provider.find(params, projection, options)
.populate([{path: 'user', match: {gender: 'F'}}]).exec((error, e) => {
if (error) {
console.log('error:', error)
return {error: error}; // returns error in json
}
return e.filter(i => i.user);
});
};
const total = await Provider.countDocuments(params).exec();
return {data(), total}
}
Thanks in advance
Use mongoose-aggregate-paginate-v2 and update your schema. If you use that package then you have to convert your queries from populate to aggregate style.
STEP 1: Update schema. Sample Schema:
const mongoose = require('mongoose');
const mongoosePaginate = require('mongoose-aggregate-paginate-v2');
const Schema = mongoose.Schema;
let definition = {
headLine: {
type: String,
required: false
},
availableDays: [{
type: Schema.Types.ObjectId,
ref: AvailableDay
}]
};
let options = {
collection: 'providers'
};
let providerSchema = new Schema(definition, options);
providerSchema.plugin(mongoosePaginate);
module.exports = mongoose.model('providers', providerSchema);
STEP 2: Update controller. Sample code in controller:
router.get('/', async (req, res) => {
const match = {}
const sort = {
// Fill it based on your sort logic.
}
const paginateOptions = {
page: req.query.page, // Page number like: 1, 2, 3...
limit: req.query.limit // Limit like: 10, 15, 20...
};
ProviderRepository
.findBy(match, {}, sort, paginateOptions)
.then(() => {
res.status(200).json(docs)
})
.catch(() => {
res.status(HTTP_ERROR_CODE).json({ "error": "Your error message" })
})
});
STEP 3: Update manager. Sample code in manager:
const findBy = (match, projection, sort, paginateOptions) => {
if (!paginateOptions) {
paginateOptions = {
pagination: false
};
}
let providerAggregate = providerSchema.aggregate([
{
$lookup: {
from: "availableDays",
let: { days: "$availableDays" },
pipeline: [
{
$match: {
$expr: {
$in: ["$$availableDays", "$day"]
}
}
}
],
as: "availableDays"
}
},
{
$lookup: {
from: "users", // I dont know the collection name
let: { user_id: "$user" }
pipeline: [
{
$match: {
"gender": 'F',
$expr: {
$eq: ["$_id", "$$user_id"]
}
}
}
],
as: "users"
}
}
{ $sort: sort }
]);
return providerSchema
.aggregatePaginate(providerAggregate, paginateOptions)
.then(res => {
return res;
})
.catch(err => {
throw err;
});
};

Why is this mongoose 'findOne' query always returning null?

I am trying to find a specific document with mongoose in my Cosmosdb with this query described below.
const mongoose = require('mongoose');
var ObjectID = require('mongodb').ObjectID
const keys = require('../config/keys');
const Item = mongoose.model('items');
const uploadToBlob = async (containerName, blobName, json, id) => {
console.log('id', id)
Item.findOne({ _id: id }, (foundItem) => {
console.log(foundItem)
});
console.log('here')
Item.findOneAndDelete({ name: blobName });
};
I am successfully able to find the document when querying like this below.
const scanMongo = () => {
Item.find({
_id: {
$gt: ObjectID.createFromTime(Date.now() / keys.mongoPurgeInterval)
}}, (err, foundItems) => {
if(err) {
console.log("Oops", err);
return;
}
foundItems.forEach(item => {
JSON.stringify(item)
const blobName = item.name;
json = "'"+item+"'"
const id = item._id
uploadToBlob(keys.containerName, blobName, json, id);
});
});
}
This is what the object I'm looking for looks like when pulled from the query above.
[ { _id: 5cabd5c6e16288230cba2cf6, name: 'test', value: 1, __v: 0 } ]
For kicks, here my model.
const mongoose = require('mongoose');
const { Schema } = mongoose;
const itemSchema = new Schema({
name: String,
value: Number,
});
mongoose.model('items', itemSchema);
I'm befuddled. Any help would be bawler. Thanks!!!
Yeah, the first parameter is supposed to catch the error.
Item.findOne({ _id: id }, (error, foundItem) => {
console.log(foundItem)

Promise.all() is slower than using await for each promise?

I'm doing some testing for performance and was looking at Promise.all() in node/js. However, after testing this it's actually slower than using await for the 3 promises I want to resolve. I'm simply returning some data back from a mongodb database.
Am I doing something wrong here or is this just due to the way the event loop is working?
Promise.all() : 234.820ms
// Init db connection
const db = client.db('docker-client1');
const productsCollection = db.collection('ICProductData');
const rulesCollection = db.collection('SPRuleData');
const customersCollection = db.collection('ARCustomerData');
// Main function
const CustomerCode = 'FINE';
const ProductCode = 'BEDCABINET';
let customers = customersCollection
.find({ _id: CustomerCode })
.project({ PriceCode: 1, BillToAccountCode: 1 })
.toArray();
let products = productsCollection
.find({ _id: ProductCode })
.project({ 'Price.PriceCode': 1, 'Price.SellingPrice': 1 })
.toArray();
let rules = rulesCollection
.find({
$and: [
{
$or: [
{
$and: [
{ What1Code: ProductCode, What1Type: 'Product' },
{ Who1Code: CustomerCode, Who1Type: 'Customer' }
]
}
]
}
]
})
.toArray();
const results = await Promise.all([customers, products, rules]);
console.timeEnd();
Simply using await : 127.239ms
// Init db connection
const db = client.db('docker-client1');
const productsCollection = db.collection('ICProductData');
const rulesCollection = db.collection('SPRuleData');
const customersCollection = db.collection('ARCustomerData');
// Main function
const CustomerCode = 'FINE';
const ProductCode = 'BEDCABINET';
const custReq = await customersCollection
.find({ _id: CustomerCode })
.project({ PriceCode: 1, BillToAccountCode: 1 })
.toArray();
const prodReq = await productsCollection
.find({ _id: ProductCode })
.project({ 'Price.PriceCode': 1, 'Price.SellingPrice': 1 })
.toArray();
let rulesReq = await rulesCollection
.find({
$and: [
{
$or: [
{
$and: [
{ What1Code: ProductCode, What1Type: 'Product' },
{ Who1Code: CustomerCode, Who1Type: 'Customer' }
]
}
]
}
]
})
.toArray();
console.timeEnd();
The method toArray() does not return a Promise in Old versions of Mongo. This could be the explanation about timings. You could put a console.log with timing after each toArray() they should run in the same millisecond (same tick). If this is not the case, it could be an indication that toArray() is waiting for the response... so you are running sequentially. You could try to resolve this with: let myProm = collection.find(filter).exec()

Categories

Resources