Create groups of matching data with some rules - javascript

I'm working in a project where people fill a form then with a Mongo aggregation that group all the people based on the date, time and place they choose.
const matchController = {
generateMatch: async (req, res) => {
const form = await Forms.aggregate([
{
$group: {
_id: { Date: "$date", Time: "$time", Place: "$place" },
Data: {
$addToSet: {
Name: "$firstName",
Surname: "$surname",
Email: "$email",
Date: "$date",
Time: "$time",
Status: "$status",
Place: "$place",
_id: "$_id"
},
},
Total: { $sum: 1 },
},
},
{
$match: {
Total: { $gte: 2 },
},
},
{ $out: "matchs" },
]);
},
But now I would like to add more complexity with some rules, for example I want each group to be made with just 2 filled forms. Also I'm thinking about allowing mutiple time selection so for example, 4 people fill the form with same date and place but:
Person 1 selects 08:00 a.M and 12:00p.M,
Person 2 selects 12:00 p.M,
Person 3 selects 8:00 a.M and 13:00 p.M,
Person 4 selects 12:00 p.m.
I want a validation so in this example instead of getting person 1 and 2 matching and person 3 and 4 free, it would check and match person 1 and 3 and person 2 and 4.
I know this question is kind of complex so any guidance on how to get there would be deeply appreciated and thanked.

Related

How to filter data of least 6 month in mongodb?

I want to get user data of the last 6 months from the current date in MongoDB. I am filtering data by status than getting the array in response. I also want to apply another query on same based on date. I want to filter it once based on last 6 months then in another query based on last 30 days from current date.
My data is -
{
_id: new ObjectId("63ac23187dc7d"),
details: 'hii there i am feeling great today',
status: '1',
createdAt: 2021-11-28T11:06:00.736Z
},
{
_id: new ObjectId("63ac23b357dc96"),
details: 'hi i am feeling good today',
status: '1',
createdAt: 2022-12-28T11:08:40.400Z,
},
{
_id: new ObjectId("63b2b2afa0d8e"),
details: 'Hello!! This is Ankit and feeling good',
status: '1',
createdAt: 2022-11-14T10:31:36.098Z
},
{
_id: new ObjectId("63b2b2sswa0d91"),
details: 'Felling bad a bit',
status: '1',
createdAt: 2023-01-02T10:32:27.149Z
},
{
_id: new ObjectId("63b2b2a0d94"),
details: 'Hmm, its ok ok',
status: '1',
createdAt: 2023-01-02T10:33:19.386Z
}
We use the $gte query operator and JavaScript's Date.now() function to retrieve all order documents with a date greater than or equal to 6 months before the current date. We will use new Date() of JavaScript to get the current date and the setMonth() method to go back 6 months.
You can try this
let sixMonths = new Date();
sixMonths.setMonth(sixMonths.getMonth() - 6);
db.collections.find({ createdAt: { $gte: sixMonths } });
For the days, you can put "1"instead of "6" which is equivalent to 1 month.

How to get average order data for days of week between two dates in mongodb aggregate?

I'm trying to get all orders between two dates, group them by day of week, then average them. Currently the code looks like this:
export const getOrderValuesBetweenTwoDates = async (
from: number,
to: number,
) => {
// from, and to are guaranteed to be Mondays, 00:00
const orders = await OrderModel.find({
createdAt: { $lt: to, $gte: from },
}).exec();
const totalOfDaysOfWeek = [0, 0, 0, 0, 0, 0, 0];
orders.forEach((order) => {
const daysSinceFrom = (order.createdAt - from) / dayInMilliseconds;
const dayOfWeek = Math.floor(daysSinceFrom) % 7;
totalOfDaysOfWeek[dayOfWeek] =
(totalOfDaysOfWeek[dayOfWeek] || 0) + order.value;
});
const numberOfWeeks = Math.floor((to - from) / dayInMilliseconds / 7);
const averageOfDaysOfWeek = totalOfDaysOfWeek.map((v) =>
Number((v / numberOfWeeks).toFixed(2)),
);
return averageOfDaysOfWeek;
};
However, this is not really performant, and I guess if it could be written in aggregation, it would be. Is that possible to convert the above into aggregation?
Sample input (2 weeks):
[
// 1st mon (total 5)
{ createdAt: 345600000, value: 2 },
{ createdAt: 345600000, value: 3 },
// 1st tue
{ createdAt: 432000000, value: 1 },
// 1st wed
{ createdAt: 518400000, value: 1 },
// 1st thu
{ createdAt: 604800000, value: 1 },
// 1st fri
{ createdAt: 691200000, value: 1 },
// 1st sat
{ createdAt: 777600000, value: 1 },
// 1st sun (2 total)
{ createdAt: 864000000, value: 2 },
// 2nd mon (1 total)
{ createdAt: 950400000, value: 1 },
// 2nd tue
{ createdAt: 1036800000, value: 1 },
// 2nd wed
{ createdAt: 1123200000, value: 1 },
// 2nd thu
{ createdAt: 1209600000, value: 1 },
// 2nd fri
{ createdAt: 1296000000, value: 1 },
// 2nd sat
{ createdAt: 1382400000, value: 1 },
// 2nd sun (4 total)
{ createdAt: 1468800000, value: 1 },
{ createdAt: 1468800000, value: 1 },
{ createdAt: 1468800000, value: 2 },
]
In the above example I've made 2 special cases, for Monday, and Sunday. There are multiple orders for those days.
For the first Monday there is an order with value 2, and 3, to 5 in total. For the second Monday there is only one order with value 1. The average should be 3.
For Sunday, the first one, there's an order with value 2, and for the second Sunday, there are 3 orders with total value of 4. I'm expecting the average to be 3.
I'm expecting the result to be [3,1,1,1,1,1,3]
format the date using $dateToString
use $sum to get sum of same day of week
get day of week by $dayOfWeek
group by days of week and get average by $avg
project to get data as desired format
weekDay in output will be number between 1 (Sunday) and 7 (Saturday).
test it at mongoPlayground
db.collection.aggregate([
{
"$addFields": {
createdAt: {
"$dateToString": {
"date": {
"$toDate": "$createdAt"
},
"format": "%Y-%m-%d"
}
}
}
},
{
"$group": {
"_id": "$createdAt",
"value": {
"$sum": "$value"
}
}
},
{
"$addFields": {
"createdAt": {
$dayOfWeek: {
"$toDate": "$_id"
}
}
}
},
{
"$group": {
"_id": "$createdAt",
"average": {
"$avg": "$value"
}
}
},
{
"$project": {
_id: 0,
weekDay: "$_id",
average: 1
}
}
])

Markov Chain with banking data

Trying to create a hidden markov model to find recurring payments in this transactions json:
https://pastebin.com/tzRaqMxk
I created a similarity score, to estimate the likely hood of a transaction date, amount, and name being a recurring transaction.
nn = require('nearest-neighbor');
const items = https://pastebin.com/tzRaqMxk //pastebin json here
var query = { amount: 89.4, name: "SparkFun", date: "2017-05-28"};
var fields = [
{ name: "name", measure: nn.comparisonMethods.word },
{ name: "amount", measure: nn.comparisonMethods.number, max: 100 },
{ name: "date", measure: nn.comparisonMethods.date, max: 31 }
];
nn.findMostSimilar(query, items, fields, function(nearestNeighbor, probability) {
console.log(query);
console.log(nearestNeighbor);
console.log(probability);
});
The first challenge is what to do if the recurring transaction is not on the same day of the month I.e. usually happens on the 18th, but because the 18th fell on a Saturday, the payment doesn't clear until the 20th. What statistical measure to I used to identify a similar score as nearly the same, but not a probability of 1.
Then after I have this array of data, how can I feed that into a hidden markov model?

Decrement many values simultaneously and positionally in mongodb

I have a collection representing robots holding an inventory of products in positional slots, which will be incremented and decremented.
{
_id: "someid",
name: "",
inventory: [{
productId: "productId1",
count: 30
}, {
productId: "productId2",
count: 56
}, {
// ... up to 55 slots.
}]
}
I then have an API that will interact with this document on a PUT request. The request data will contain the index of the inventory to update and the number to decrement it by, eg:
[
{ "inventory": 3, "inc": -10 }, // remove 10 from robot.inventory[3]
{ "inventory": 54, "inc": -2 }, // remove 2 from robot.inventory[10]
]
I have the following code.
// robots submit to this api to keep their products up to date
MachineApiV1.addRoute('/products', {
authRequired: true,
roleRequired: 'machine'
}, {
put: function () {
// omit process to get data from above
var user = Users.findOne(this.request.headers['x-user-id']);
Robots.update(user.profiles.robot, {
$inc: { } // this is where I am lost.
});
}
});
I can't quite think of a way to do it in a single update. How can I increment multiple arbitrary indexes in a mongo document?
MongoDB makes it really simple - just specify the position in the array of sub-documents you want to update:
Robots.update(user.profiles.robot, {
$inc: {
'inventory.3.count': -10,
'inventory.54.count': -2
}
});

MongoDB aggregate merge two different fields as one and get count

I have following data in MongoDB:
[{id:3132, home:'NSH', away:'BOS'}, {id:3112, home:'ANA', away:'CGY'}, {id:3232, home:'MIN', away:'NSH'}]
Is it possible to get total game count for each team with aggregate pipeline?
desired result:
[{team: 'NSH', totalGames: 2}, {team:'MIN', totalGames: 1}, ...}]
i can get each on seperately to their own arrays with two aggregate calls:
[{$group: {_id: "$home", gamesLeft: {$sum: 1}}}]
and
[{$group: {_id: "$away", gamesLeft: {$sum: 1}}}]
resulting
var homeGames = [ { _id: 'NSH', totalGames: 1 }, { _id: 'SJS', totalGames: 2 }, ...]
var awayGames = [ { _id: 'NSH', totalGames: 1 }, { _id: 'SJS', totalGames: 4 }, ...]
But i really want to get it working with just one query. If not possible what would be the best way to combine these two results in to one using javascript?
After some puzzling, I found a way to get it done using an aggregate pipeline. Here is the result:
db.games.aggregate([{
$project: {
isHome: { $literal: [true, false] },
home: true,
away: true
}
}, {
$unwind: '$isHome'
}, {
$group: {
_id: { $cond: { if: '$isHome', then: '$home', else: '$away' } },
totalGames: { $sum: 1 }
}
}
]);
As you can see it consists of three stages. The first two are meant to duplicate each document into one for the home team and one for the away team. To do this, the project stage first creates a new isHome field on each document containing a true and a false value, which the unwind stage then splits into separate documents containing either the true or the false value.
Then in the group phase, we let the isHome field decide whether to group on the home or the away field.
It would be nicer if we could create a team field in the project step, containing the array [$home, $away], but mongo only supports adding array literals here, hence the workaround.

Categories

Resources