The shape of the documents I'm using look similar to this:
{
"survey_id": 123,
"numerical_answers": [
{
"component_id": 345,
"number": 5,
},
{
"component_id": 346,
"number": 5,
}
]
}
The output of ArangoDB should look like this:
[
{
"component_id": 345,
"distribution": [
{
"component_id": 345,
"score": null,
"total": 42
},
{
"component_id": 345,
"score": 1,
"total": 76
},
{
"component_id": 345,
"score": 2,
"total": 37
},
{
"component_id": 345,
"score": 3,
"total": 40
},
{
"component_id": 345,
"score": 4,
"total": 93
},
{
"component_id": 345,
"score": 5,
"total": 212
}
],
"total": 500,
"avg": 3.404
}
]
My AQL looks like this:
FOR doc IN ##collection
FILTER doc.`survey_id` == #survey_id
LET componentScoreGroup = {
component_id: #component_id,
score: FIRST(doc.numerical_answers[* filter CURRENT.component_id == #component_id return CURRENT.number])
}
COLLECT component_id = componentScoreGroup.component_id, score = componentScoreGroup.score WITH COUNT INTO total
LET distribution = {
component_id: component_id,
score: score,
total: total
}
COLLECT component_id2 = distribution.component_id into groups keep distribution
LET finalTotal = sum(groups[*].distribution.total),
summedScore = sum(groups[* return CURRENT.distribution.score * CURRENT.distribution.total])
RETURN {
component_id: component_id2,
distribution: groups[*].distribution,
total: finalTotal,
avg: summedScore / finalTotal
}
I would like to use the more performant AGGREGATE syntax in the COLLECT but I'm not sure I can because I also want to pull in the distribution content in the final return.
Any help would be greatly appreciated!
is this closer to what you are looking for?
FOR doc IN ##collection
FILTER doc.survey_id == #survey_id
LET componentScoreGroup = {
component_id: #component_id,
score: FIRST(doc.numerical_answers[* filter CURRENT.component_id == #component_id return CURRENT.number])
}
COLLECT id = componentScoreGroup.component_id
AGGREGATE avg = AVG(componentScoreGroup.score),
total = SUM(componentScoreGroup.score)
INTO group
return { "id" : id , "avg" : avg , "total" : total, "number" : LENGTH(group), "group" : group}
Related
I have a json data like this.
[{
"name": "Peter",
"age": 30,
"hair color": "brown"
}, {
"name": "Steve",
"age": 55,
"hair color": "blonde"
}, {
"name": "Steve",
"age": 25,
"hair color": "black"
}]
My code it does is, It will identify the duplicate and remove the second occurrence.
The code is :
var qdata = [{
"name": "Peter",
"age": 30,
"hair color": "brown"
}, {
"name": "Steve",
"age": 55,
"hair color": "blonde"
}, {
"name": "Steve",
"age": 25,
"hair color": "black"
}]
data = qdata.filter((obj, pos, arr) => {
return arr.map(mapObj =>
mapObj.name).indexOf(obj.name) == pos;
});
console.log(data);
Output will be :
[
{ name: 'Peter', age: 30, 'hair color': 'brown' },
{ name: 'Steve', age: 55, 'hair color': 'blonde' }
]
Here it deletes the second occurrence and keeps the first one, But what I would like to get is remove the first occurrence and keep the second one
[
{ name: 'Peter', age: 30, 'hair color': 'brown' },
{ name: 'Steve', age: 25, 'hair color': 'black' }
]
How can I do that ? Please help
You can simply reverse the array and do what you want and reverse the result to match with your expected result.
qdata.reverse();
data = qdata.filter((obj, pos, arr) => {
return arr.map(mapObj => mapObj.name).indexOf(obj.name) == pos;
});
console.log(data.reverse());
if you don't want to do that you can use the below code to get desired result.
data = [];
qdata.map((i) => {
index = data.findIndex((u) => u.name === i.name);
if (index >= 0) {
data.splice(index, 1, i);
} else {
data.push(i);
}
});
console.log(data);
I want to decrement slotsAvailable by 1 and increment slotsBooked by 1 if provide courtId is equal to courtId which in slotTracker and provided date is there in dates array
Sample Data
{
"slotTracker" : [
{
"courtID" : 1,
"dates" : [
{
"date": "2021-03-17T08:03:02.197Z",
"slotsBooked": 0,
"slotsAvailable": 10
},
{
"date": "2021-04-17T08:03:02.197Z",
"slotsBooked": 0,
"slotsAvailable": 15
},
]
},
{
"courtID" : 2,
"dates" : [
{
"date": "2021-03-17T08:03:02.197Z",
"slotsBooked": 0,
"slotsAvailable": 15
},
{
"date": "2021-04-17T08:03:02.197Z",
"slotsBooked": 0, //increase this by 1
"slotsAvailable": 5 //decrease this by 1
},
]
}
]
}
for example: provided courtId is 1 and provided date is "2021-03-17T08:03:02.197Z". so it will change the slotAvailable couter
{
"courtID" : 2,
"dates":[{
"date": "2021-04-17T08:03:02.197Z",
"slotsBooked": 1, //increase this by 1
"slotsAvailable": 4 //decrease this by 1
},
{
"date": "2021-03-17T08:03:02.197Z",
"slotsBooked": 0,
"slotsAvailable": 15
},
]
}
db.sample.update({
courtID: 2,
"dates.date" : "2021-04-17T08:03:02.197Z"
} ,
{$inc : {
"dates.$.slotsBooked" : 1, "dates.$.slotsAvailable" : -1}
});
Please try this out :)
I've problem to find remaining seats of particular restaurant in a particular Date range
Let me define my problem. Suppose I've a collection it called booking
In this have a following fields:
Booking ID
User ID
Restaurant ID
Booking Start Date (date saved in Timestamp)
Booking End Date (date saved in Timestamp)
Booked Seat
If there are 50 seats in restaurant. And I want to check available seats of a particular date range for example the date range is 6-12(This range in timestamp)"(Start Date) - (End Date)"
How to calculate the total remaining seats of restaurant.
If anyone have any idea please let me know.
Thanks in advance
Code is here
const where = {};
where.restaurant_id = 126;
where.user_id = 1;
where.start_date = { $gte: 6 };
where.end_date = { $gte: 12 };
const remainingSeats = getSeatsAvailability(where);
function getSeatsAvailability(where) {
return new Promise((resolve, reject) => {
bookingModel.find(where, (err, details) => {
if (err) { reject(err); } else { resolve(details); }
});
});
}
So, What I have Visualized is the below diagram, so there are basically four cases to be covered:
x y
a-----------|---------b |
a-|------------|---b
| a-------b |
| a-----|--------b
So the formulae are:
1. a<x, a<y | b>x, b<y
2. a<x, a<y | b>x, b>y
3. a>x, a<y | b>x, b>y
4. a>x, a<y | b<y, b>x
I am pasting an ROUGH example, take it as a hint to solve the problem at hand:
db.collection.aggregate([
{
$match: {
$or: [
{
a: {
$lte: 3,
$lte: 9
},
$or: [
{
b: {
$gte: 3,
$lte: 9
}
},
{
b: {
$gte: 3,
$gte: 9
}
}
]
},
{
a: {
$gte: 3,
$lte: 9
},
$or: [
{
b: {
$gte: 3,
$gte: 9
}
},
{
b: {
$gte: 3,
$lte: 9
}
}
]
}
],
r: 1
}
},
{
$group: {
_id: null,
sum_booked: {
$sum: "$c"
}
}
},
{
$project: {
seats_left: {
$subtract: [
50,
"$sum_booked"
]
}
}
}
])
The example dataset that I have tested on:
[
{
a: 1,
b: 10,
c: 10,
r: 1,
},
{
a: 2,
b: 5,
c: 15,
r: 1
},
{
a: 5,
b: 10,
c: 10,
r: 1
},
{
a: 7,
b: 15,
c: 15,
r: 12 <<<<========/////DIFF REST ID
}
]
Output:
[
{
"_id": null,
"seats_left": 15
}
]
db.booking.aggregate([{
$match: {
BookingStartDate: { $lte: date_range_end },
BookingEndDate: { $gte: date_range_start },
RestaurantID: restaurant_id
}
},
{
$group: {
_id: '$RestaurantID',
TotalBookedSeat: { $sum: '$BookedSeat' }
}
},
{
$project: {
LeftSeat: { $subtract: [50, '$TotalBookedSeat'] },
_id: 0
}
}
])
{ "_id" : ObjectId("5d8479f6902a52448029a6d0"), "bid" : 1, "uid" : 1, "rid" : 126, "bsd" : 1, "bed" : 10, "bs" : 10 }
{ "_id" : ObjectId("5d847a11902a52448029a6d1"), "bid" : 2, "uid" : 1, "rid" : 126, "bsd" : 2, "bed" : 5, "bs" : 15 }
{ "_id" : ObjectId("5d847a24902a52448029a6d2"), "bid" : 3, "uid" : 1, "rid" : 126, "bsd" : 5, "bed" : 10, "bs" : 10 }
{ "_id" : ObjectId("5d847a34902a52448029a6d3"), "bid" : 4, "uid" : 1, "rid" : 126, "bsd" : 7, "bed" : 15, "bs" : 15 }
db.booking.aggregate([{ $match: { bsd: { $lte: 12 }, bed: { $gte: 6 }, rid: 126 } }, { $group: { _id: '$rid', total_seat_sold: { $sum: '$bs' } } }])
The result of the above is 35, then 15 seats left.
This time it will works I think.
I have schema:
{
userName: String
postCount: Number,
commentCount: Number,
abuseCount: Number,
}
I need get sum all users counts all fields in result
example
{
"userName": "John"
"postCount": 5,
"commentCount": 1,
"abuseCount": 4,
}, {
"userName": "Bob"
"postCount": 11,
"commentCount": 41,
"abuseCount": 3,
}, {
"userName": "Alex"
"postCount": 2,
"commentCount": 15,
"abuseCount": 6,
}
result must be ~
{
"postCount": 18, (sum all postCount field users)
"commentCount": 57,
"abuseCount": 10,
}
How I can do this? Thx!
Imagine I had a collection called journals containing documents like the following:
{
"article": "id1",
"d": 2
},
{
"article": "id1",
"d": 2
},
{
"article": "id1",
"d": 3
},
{
"article": "id2",
"d": 2
},
...
Where d is kind of a switch and article is a reference. Now I want to have a result like the following:
[
{
"_id": "id1",
"total": 3,
"d2": 2,
"d3": 1
},
{
"_id": "id2",
"total": 1,
"d2": 1,
"d3": 0
}
]
I'm using mongoose and have a model called Journal. What I've got so far is…
Journal.aggregate(
{ $project: {
articleId: 1,
depth2 : { $gte:['$d', 2] },
depth3 : { $eq:['$d', 3] }
}},
{ $group: {
_id: '$article',
total: { $sum: 1 },
d2: { $sum: '$depth2'},
d3: { $sum: '$depth3'}
}
},
function (err, journal) {
console.log(journal);
}
);
which results in:
[
{
"_id": "id1",
"total": 3,
"d2": 0,
"d3": 0
},
{
"_id": "id2",
"total": 1,
"d2": 0,
"d3": 0
}
]
Obviously the error here is that $eq:['$d', 3] is not summed up because that results in a boolean.
So is there a better expression that projects the new depth2 and depth3 fields to 1or 0 instead of true or false?
Or is there a complete and better approach? :)
I'd like to avoid making 3 queries and prepending a matching phase like { $match: { d: 2 } }.
You can use $cond to convert a boolean to a numerical value, but you've also got a $gte where it seems an $eq should be and your docs use article while your code uses articleId:
Journal.aggregate([
{ $project: {
article: 1,
depth2 : { $cond: [{$eq: ['$d', 2]}, 1, 0] },
depth3 : { $cond: [{$eq: ['$d', 3]}, 1, 0] }
}},
{ $group: {
_id: '$article',
total: { $sum: 1 },
d2: { $sum: '$depth2'},
d3: { $sum: '$depth3'}
}
}
]);
Output:
{
"result" : [
{
"_id" : "id2",
"total" : 1,
"d2" : 1,
"d3" : 0
},
{
"_id" : "id1",
"total" : 3,
"d2" : 2,
"d3" : 1
}
],
"ok" : 1
}