How to make Sequelize search by several fields? - javascript

I spent a lot of time to find an answer, but did not find it
So, my problem is - I am trying to make where condition like this:
where: {
[Op.and]:
[
{ skill: 'IDE', months: { [Op.gte]: 28 } },
{ skill: 'REST', months: { [Op.gte]: 20 } },
]
}
But it just does not work
May be it is not right way to do what i need?

probably you want an or like that.
const { Op } = require("sequelize");
Post.findAll({
where: {
[Op.or]: [
{ authorId: 12 },
{ authorId: 13 }
]
}
});

I think you can not use it that. You can try below codes.
where: {
[Op.and]:
[
{ [Op.and]:[{skill:'IDE'},{months:{[Op.gte]:28}] },
{ [Op.and]:[{skill:'REST'},{months:{[Op.gte]:20}] },
]
}

Related

how to catch mongo change streams when one key in object gets updated

I am using the mongo change stream to update some of my data in the cache. This is the Documentation i am following.
I want to know when one of the keys in my object gets updated.
Schema :- attributes: { position: { type: Number } },
How will I come to know when the position will get updated?
This is how my updateDescription object looks like after updation
updateDescription = {
updatedFields: { 'attributes.position': 1, randomKey: '1234'},
removedFields: []
}
Tried this and its not working
Collection.watch(
[
{
$match: {
$and: [
{ operationType: { $in: ['update'] } },
{
$or: [
{ 'updateDescription.updatedFields[attributes.position]': { $exists: true } },
],
},
],
},
},
],
{ fullDocument: 'updateLookup' },
);
I was able to fix it like this,
const streamUpdates = <CollectionName>.watch(
[
{
$project:
{
'updateDescription.updatedFields': { $objectToArray: '$updateDescription.updatedFields' },
fullDocument: 1,
operationType: 1,
},
},
{
$match: {
$and: [
{ operationType: 'update' },
{
'updateDescription.updatedFields.k': {
$in: [
'attributes.position',
],
},
},
],
},
},
],
{ fullDocument: 'updateLookup' },
);
and then do something with the stream
streamUpdates.on('change', async (next) => {
//your logic
});
Read more here MongoDB

Mongoose return grouped by date

My model is the following :
const scheduleTaskSchema = new Schema({
activity: { type: Object, required: true },
date: { type: Date, required: true },
crew: Object,
vehicle: Object,
pickups: Array,
details: String,
});
pickups is an array of objects with the following structure :
{
time : //iso date,
...rest //irrelevant
}
i want to return my data grouped by date,and also every group within has to be sorted by pickup[0].time so it will finally return something like this example :
{
"2022-08-28T00:00:00.000+00:00": [
{
date: "2022-08-28T00:00:00.000+00:00",
pickups: [
{
time: "2022-08-28T07:30:00.000Z",
...rest //irrelevant
}
],
...rest //irrelevant
},
{
date: "2022-08-28T00:00:00.000+00:00",
pickups: [
{
time: "2022-08-28T09:30:00.000Z",
...rest //irrelevant
}
],
...rest //irrelevant
}
]
,
"2022-08-29T00:00:00.000+00:00": [
{
date: "2022-08-29T00:00:00.000+00:00",
pickups: [
{
time: "2022-08-29T10:00:00.000Z",
...rest //irrelevant
}
],
...rest //irrelevant
},
{
date: "2022-08-29T00:00:00.000+00:00",
pickups: [
{
time: "2022-08-29T11:30:00.000Z",
...rest //irrelevant
}
],
...rest //irrelevant
}
]
}
You need to use the aggregation framework for this.
Assuming the dates are exactly the same (down to the millisecond), your code would look something like this.
const scheduledTasksGroups = await ScheduledTask.aggregate([{
$group: {
_id: '$date',
scheduledTasks: { $push: '$$ROOT' }
}
}]);
The output will be something like:
[
{ _id: "2022-08-29T10:00:00.000Z", scheduledTasks: [...] },
{ _id: "2022-08-28T10:00:00.000Z", scheduledTasks: [...] }
]
If you want to group by day instead of by millisecond, your pipeline would look like this:
const scheduledTasksGroups = await ScheduledTask.aggregate([{
$group: {
// format date first to `YYYY-MM-DD`, then group by the new format
_id: { $dateToString: { format: '%Y-%m-%d', date: '$date' } },
scheduledTasks: { $push: '$$ROOT' }
}
}]);
For what it's worth, this is a MongoDB feature, the grouping happens on the MongoDB server side; mongoose doesn't do anything special here; it just sends the command to the server. Then the server is responsible for grouping the data and returning them back.
Also, keep in mind that mongoose does not cast aggregation pipelines by default, but this plugin makes mongoose cast automatically whenever possible.

Map the nested data from other table using promise and async-await

I need the expert advice for this code. I need to know Is there any better way to solve this.
I am using the mongoose for db. I have a dataset like this:
Below is matchTable:
{
_id: 617bc0113176d717f4ddd6ce,
car: [],
status: true
},
{
_id: 617bc0113176d717f4ddd6cg,
car: [
{
aid: '5c1b4ffd18e2d84b7d6febcg',
}
],
status: true
}
And I have a Car table in which car name is there on behalf of id
like this
{ _id: ObjectId('5c1b4ffd18e2d84b7d6febce'), name: 'ford' },
{ _id: ObjectId('5c1b4ffd18e2d84b7d6febcg'), name: 'mitsubishi' },
So I want to make join the data from car table, so that response get name on behalf of aid.
Desired result will be like
{
_id: 617bc0113176d717f4ddd6ce,
car: [],
status: true
},
{
_id: 617bc0113176d717f4ddd6cg,
car: [
{
aid: '5c1b4ffd18e2d84b7d6febcg',
name: 'mitsubishi'
}
],
status: true
}
For that I have to merge the car table on matchTable. I have done this but I want to give some suggestion that is there any better way to do or is it fine. I need expert advice.
const getData = await matchTable.find(
{ status: true }
).lean().exec();
let dataHolder = [];
await Promise.all (
getData.map(async x => {
await Promise.all(
x.car.map(async y => {
let data = await Car.findOne(
{ _id: ObjectId(y.aid) },
{ name: 1 }
).lean().exec();
y.name = '';
if (data) {
y.name = data.name;
}
})
)
// If I return { ...x }, then on response it will return {}, {} on car column
dataHolder.push(x) //So I have chosen this approach
})
);
Please guide me if any better and efficient solution is there. Thanks in advance
You can make use of aggregation here.
const pipeline = [
{
$match : { status : true }
},
{
$unwind: '$matchtable',
},
{
$lookup: {
from: "cars",
localField: "car.aid",
foreignField: "_id",
as: "matchcars"
}
},
{
$addFields: {
"car.carName": { $arrayElemAt: ["$matchcars.name", 0] }
}
},
{
$group: {
_id: "$_id",
cars: { $push: "$matchcars" }
}
}
]
const result = await matchTable.aggregate(pipeline).exec();
Please make sure, aid field inside car array (in matchTable collection) is an ObjectId because its being matched to _id (which is an ObjectId) inside cars collection.

$subtract not working with $set in mongodb

I am using the following query to update the documents in mongodb but it throws me the error The dollar ($) prefixed field '$subtract' in 'abc.$subtract' is not valid for storage.
const bulkUpdate = arrs.map(arr => {
const { val = 0 } = arr
return {
updateMany: {
filter: {
date: 20201010
},
update: {
$set: {
abc: {
$subtract: [val, { $add: [{ $ifNull: ['$a1', 0] }, { $ifNull: ['$b1', 0] } ] }]
}
},
},
},
}
})
if (bulkUpdate.length > 0) {
return mongoConnection.pool
.db('test')
.collection('testTable')
.bulkWrite(bulkUpdate)
}
Thanks is advance
$subtract and $ifNull are not update operators, hence you can't use them within an update (except a within a pipelined update).
If you're using Mongo version 4.2+ you can use use a pipeline update instead of a "document update" like so:
{
updateMany: {
filter: {
date: 20201010
},
update: [
{
$set: {
abc: {
$subtract: [val, {$add: [{$ifNull: ['$a1', 0]}, {$ifNull: ['$b1', 0]}]}]
}
}
}
]
}
}
If you aren't then you'll have to read each document and update it sepratley as prior to version 4.2 you could not access document fields while updating as you are trying to do.

Problem with countDocuments Mongoose: its not actually waiting for the callback function to execute

I've a problem with a Mongoose backend. i guess its an asynchronous problem. Can someone try to explain me how countDocuments works?
albumFields.features = [];
for await (const feature of features) {
await Artist.countDocuments({ _id: feature._id }, (err, count) => {
if (count > 0) {
albumFields.features.push({ _id: feature._id });
}
console.log('artist.count', albumFields.features);
});
console.log('features.forEach', albumFields.features);
}
console.log('!!!', albumFields.features);
the output im getting is:
artist.count [ { _id: '5ec09f9c99339f3ad85973c0' } ]
features.forEach [ { _id: '5ec09f9c99339f3ad85973c0' } ]
features.forEach [ { _id: '5ec09f9c99339f3ad85973c0' } ]
!!! [ { _id: '5ec09f9c99339f3ad85973c0' } ]
artist.count [ { _id: '5ec09f9c99339f3ad85973c0' },
{ _id: '5ec09fb199339f3ad85973c4' } ]
The output i would expect is:
artist.count [ { _id: '5ec09f9c99339f3ad85973c0' } ]
features.forEach [ { _id: '5ec09f9c99339f3ad85973c0' } ]
artist.count [ { _id: '5ec09f9c99339f3ad85973c0' },
{ _id: '5ec09fb199339f3ad85973c4' } ]
features.forEach [ { _id: '5ec09f9c99339f3ad85973c0' },
{ _id: '5ec09fb199339f3ad85973c4' } ]
!!! [ { _id: '5ec09f9c99339f3ad85973c0' },
{ _id: '5ec09fb199339f3ad85973c4' } ]
So the problem is countDocuments() will return a promise only if there is no call back function. In our case we created the callback which gets the number of documents matching the filter.
I am not sure why the code executed the way it did so maybe someone can explain but I did manage to solve the problem.
let arraytest = [];
for (const feature of features) {
await Artist.countDocuments({ _id: feature._id }).then((count) => {
if (count > 0) {
albumFields.features = [
...albumFields.features,
{ _id: feature._id },
];
}
});
}
For anyone else who runs into the same problem, there was a link on the mongoose documentation which is easy to miss.
https://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#countDocuments

Categories

Resources