Mongodb double query - mongodb

I have following MongoDb collection:
{
"id":1,
"isBig": true } {
"id":2,
"isBig": true } {
"id":3,
"isBig": true } {
"id":4,
"isBig": true } {
"id":5,
"isBig": false } {
"id":6,
"isBig": false } {
"id":7,
"isBig": false }
I'd like to choose four random items: 2 should be big and 2 not. My attempt:
db.aggregate([
{ $match: { isBig: true } },
{ $sample: { size: 2 } }
]).toArray()
This choose only two big. I would need also two not big. COndition is I can access database only one time.

Related

MongoDB update a specific nested field

Hi I am trying to update nested filed , but couldn't able to do so.
Here is the sample data,
[{
"_id": {
"$oid": "632ec4128f567511dcd80ed9"
},
"company_id": 1,
"contact_id": 1001,
"roles_to_be_accepted": {
"ROLE#04": {
"assigned_data": {
"assigned_3HFui": {
"is_idle": false,
"send_for_acceptance_date": 1664009233,
"action_date": ""
},
"assigned_b1J9t": {
"is_idle": false,
"send_for_acceptance_date": 1664009233,
"action_date": ""
}
}
},
"ROLE#02": {
"assigned_data": {
"assigned_uPJI1": {
"is_idle": false,
"send_for_acceptance_date": 1664009233,
"action_date": ""
}
}
}
}
}]
Now I want to update that is_idle field to true. I have tried in this way
let query = { contact_id: 1, company_id: 1001};
const db = this.client.db("dbname");
const col= db.collection("collection_name");
col.update(query, {
'$set': { "roles_to_be_accepted.assigned_data.is_idle": true }
});

$elemMatch on array of objects

My schema has 6 attributes of type Array, which can each contain objects, like this:
alpha : Array
0 : Object
linkedID : "62495a66fb140b240476d8ff"
verified : false
1 : Object
linkedID : "62494fd789291c4f58bdad86"
verified : true
...
I want to write a query that returns a document where at least one of these Arrays contains an object that has the attribute verified == false. I've tried with $elemMatch:
myModel.findOne(
{$or: [
{ alpha: { $elemMatch: { verified: false } } },
{ beta: { $elemMatch: { verified: false } } },
{ gamma: { $elemMatch: { verified: false } } },
{ delta: { $elemMatch: { verified: false } } },
{ epsilon: { $elemMatch: { verified: false } } },
{ zeta: { $elemMatch: { verified: false } } }
] }
)
But this didn't work. I think this may be because it's a nested object, but I have no idea how to solve this. I'd really appreciate any advice.

Statistics with Mongo DB

I have the following DB structure :
{
"uploadedAt": "2021-09-22T22:09:12.133Z",
"paidAt: "2021-09-30T22:09:12.133Z",
"amount": {
"currency": "EUR",
"expected": 70253,
"paid": 0
},
}
I would like to know how do I calculate the total amount that still need to be paid (expected - paid), and the average date between uploadedAt and paidAt. This for multiple records.
My function for getting the data is (the criteria should be updated to get this data).
const invoiceParams = new FindParams();
invoiceParams.criteria = { company: company._id }
const invoices = await this.findAll(invoiceParams);
FindAll function looks like:
async findAll(
params: FindParams,
ability?: Ability,
includeDeleted: boolean = false,
): Promise<Entity[]> {
let queryCriteria: Criteria = params.criteria;
let query: DocumentQuery<Entity[], Entity> = null;
if (!includeDeleted) {
queryCriteria = {
...queryCriteria,
deleted: { $ne: true },
};
}
try {
if (ability) {
ability.throwUnlessCan('read', this.entityModel.modelName);
queryCriteria = {
...toMongoQuery(ability, this.entityModel.modelName),
...queryCriteria,
};
}
query = this.entityModel.find(queryCriteria);
if (params.populate) {
query = query.populate(params.populate);
}
if (params.sort) {
query = query.sort(params.sort);
}
if (params.select) {
query = query.select(params.select);
}
return query.exec();
} catch (error) {
if (error instanceof ForbiddenError) {
throw new ForbiddenException(error.message);
}
throw error;
}
}
Update:
const paymentTime = await this.invoiceModel.aggregate([
{
$group: {
_id: "$account",
averageSpread: { $avg: { $subtract: ["$paidAt", "$uploadedAt"] } },
count: { $sum: 1 }
}
}
]);
Try this aggregation pipeline:
db.invoiceParams.aggregate([
{
$set: {
expectedPaid: { $subtract: ["$amount.expected", "$amount.paid"] },
averageDate: { $toDate: { $avg: [{ $toLong: "$uploadedAt" }, { $toLong: "$paidAt" }] } }
}
}
])

How to create multiple groups from a single selection in Mongoose?

I would like to select all events with a certain type from an events collection and then return 2 different groups using a single selection.
For example I currently have the following 2 selections:
const sessions = await Event.aggregate([
{
$match: {
isAdmin: { $ne: true }
}
}, {
$group: {
_id: '$sessionId'
}
}
]);
const users = await Event.aggregate([
{
$match: {
isAdmin: { $ne: true }
}
}, {
$group: {
_id: '$userId'
}
}
]);
I would like to achieve an end result of:
{
numberOfSessions: sessions.length,
numberOfUsers: users.length
}
By using a single query.
Thanks in advance!
You could use facet aggregation pipeline which will provide the capability to create multi-dimensions data within a single stage. For Eg:
const sessions = await Event.aggregate([
{
$match: {
isAdmin: { $ne: true }
}
}, {
$facet: {
sessions: [{
$sortByCount: "$sessionId"
}],
users: [{
$sortByCount: "$userId"
}]
}
}
]);

Sum object key by key with Mongo on Node

I'm trying to group all this object in one, the idea is to combine all the object.
My function know is like this:
app.get('/stats/:id(\\d+)/weapon/:weapon', function(req, res, next) {
db.collection('stats').aggregate( [
{ $match: { _id: parseInt(req.params.id, 10) } },
{ $unwind: "$session" },
{ $addFields: { weapon: { $objectToArray: '$session.weapons.' + sanitize(req.params.weapon) }, _id: false } },
{ $addFields: { weapon: { $arrayToObject: "$weapon" } } },
{ $project: { weapon: "$weapon", _id: false } }
], function(err, doc) {
if( !err ) {
res.json(doc);
}
else {
console.log(err);
res.end();
}
});
});
and return something like this:
[
{
"weapon":{
"shots":30,
"hitbox":{
"head":7,
"chest":4
},
"kills":4,
"dmg":590
}
},
{
"weapon":{
"shots":46,
"kills":4,
"hitbox":{
"head":3,
"chest":4,
"stomach":3,
"left_leg":2
},
"hs":3,
"dmg":479
}
},
{
"weapon":{
"shots":30,
"hitbox":{
"head":7,
"chest":4
},
"kills":4,
"dmg":590
}
}
]
My idea is to return only one instance of weapon with the sum key by key.
I already try $group and concat array but i can't get the result that i want...
I want like this:
[
{
"weapon":{
"shots":160,
"hitbox":{
"head":17,
"chest":12,
"stomach":3,
"left_leg":2
},
"kills":12,
"hs":3,
"dmg":1659
}
}
]