Mongodb aggregate push with index value of array - javascript

I am stucked in one aggregate query, Following is my data
Let database = [
{
_id: 'fefesf', name: 'John', info: {date: ISODate(), marks: '12'}
},
{
_id: 'uiuioo', name: 'John', info: {date: ISODate(), marks: '15'}
},
{
_id: 'erygbo', name: 'Ben', info: {date: ISODate(), marks: '18'}
}]
and my aggregate query is
var query = [{
$group: {
_id: '$name',
Marks: {
$push: {
x: '$index', ..............(not working right now)
y: '$info.marks'
}
}
}
}]
Is it possible to get index of grouped document as 'x' while pushing it in 'Marks' array. Like Output should be
[
{_id: 'John', Marks: [{x: 1, y: 12}, {x: 2, y: 15}]},
{_id: 'Ben',{x: 1, y: 18}}
]
Thanks in advance.!

Since mongoDB version 3.6 you can use $reduce for that*:
db.collection.aggregate([
{
$group: {
_id: "$name",
Marks: {$push: {y: "$info.marks"}}
}
},
{$project: {
Marks: {
$reduce: {
input: "$Marks",
initialValue: [],
in: {$concatArrays: [
"$$value",
[
{
y: "$$this.y",
x: {$add: [{$size: "$$value"}, 1]}
}
]
]
}
}
}
}
}
])
See how it works on the playground example
*Inspired by this answer

Related

Filter object from array of objects

I have a object
let data1 =
{
_id: "61d576ecb87f099d033a1930",
name: 'Milk',
quality: 'premium',
price: 10,
quantity: 10,
bagSize: '10',
bagCount: 10,
status: 'Process',
sellerDetails: [ [Object] ],
image: '/uploads/milk.jpg'
}
and I have array of objects
let data2 = [
{
_id: "61d576ecb87f099d033a1930",
name: 'Milk',
quality: 'Premium',
price: 10,
quantity: 10,
bagSize: '10',
bagCount: 10,
status: 'Process',
sellerDetails: [ [Object] ],
image: '/uploads/premium.jpg'
},
{
_id: "61d576ecb87f099d033a1931",
name: 'Haldi',
quality: 'Eagle',
price: 10,
quantity: 10,
bagSize: '10',
bagCount: 10,
status: 'Process',
sellerDetails: [ [Object] ],
image: '/uploads/rai.jpg'
}
]
Now I want to filter out data1 value from data2 so the expected result after filter should be
let data2 = [
{
_id: "61d576ecb87f099d033a1931",
name: 'Haldi',
quality: 'Eagle',
price: 10,
quantity: 10,
bagSize: '10',
bagCount: 10,
status: 'Process',
sellerDetails: [ [Object] ],
image: '/uploads/rai.jpg'
}
]
I have tried,
function filteredData(data1,data2){
const filtered = data1._id !== data2._id
return filtered
}
const filteredArr = data2.filter(filteredData)
Also I have referred this
How can I acheive my expected result, am I doing something completely wrong ?
The following probably does what you want (untested).
Read up on the filter() documentation #: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
and map() #: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
data2.filter(el => {
return data1._id !== el._id;
}

Mongo $facet get and count the tags of the matched products in aggregation pipeline

I have this aggregation pipeline:
aggregate.lookup({
from: 'tags',
localField: 'tags',
foreignField: '_id',
as: 'tags'
});
aggregate.match({
productType: 'product',
available: true,
categories: {
$elemMatch: {
url: '/category/test'
}
}
});
aggregate.facet({
products: [
{ $sort: { [order]: sort } },
{ $skip: skip },
{ $limit: pageSize },
{
$project: {
_id: 1,
images: 1,
onSale: 1,
price: 1,
quantity: 1,
slug: 1,
sale: 1,
sku: 1,
status: 1,
title: 1,
brand: 1,
tags: 1
}
}
],
tags: [
{ $unwind: '$tags' },
{
$group: {
_id: {
name: '$name.label',
slug: '$slug'
},
count: {
$sum: 1
}
}
}
],
range: [
{
$bucketAuto: {
groupBy: '$price',
buckets: 1,
output: {
min: { $min: '$price' },
max: { $max: '$price' }
}
}
}
],
total: [{ $group: { _id: null, count: { $sum: 1 } } }]
});
aggregate.addFields({
total: {
$arrayElemAt: ['$total', 0]
}
});
aggregate.addFields({
range: {
$arrayElemAt: ['$range', 0]
}
});
Every product has it's own tags and I can't figure out how to:
Get the tags that belong only to the matched products and return an array from the $facet that contains
tags: [{name: 'tag1', slug: 'slug1', count: 10}, {name: 'tag2', slug: 'slug2', count: 5} ]
Where count: 10 are the products that have the tag.
Right now it returns all the tags found in the database.
2. Why the range property returns an object like this:
"range": {
"_id": {
"min": 5.9,
"max": 47
},
"min": 5.9,
"max": 47
}
and not like this since i provide an output object in $bucketAuto:
"range": {
"min": 5.9,
"max": 47
}
As of 2, this is normal mongodb behavior for $bucketAuto.
Here's what i've done and it works:
just right before $facet:
aggregate.lookup({
from: 'tags',
let: { tags: '$tags' },
pipeline: [
{
$match: {
$expr: { $in: ['$_id', '$$tags'] }
}
}
],
as: 'tags'
});
and then inside $facet:
tags: [
{ $unwind: { path: '$tags' } },
{
$group: {
_id: '$tags',
count: {
$sum: 1
}
}
}
],

How to sum key value of all documents

I am just new to Mongo DB an facing problem in summation of the key value of all documents...
Here I am providing the sample data of Mongo DB-
{ _id: 1, cust_id: "abc1", ord_date: ISODate("2012-11-02T17:04:11.102Z"), status: "A", amount: 50 }
{ _id: 2, cust_id: "xyz1", ord_date: ISODate("2013-10-01T17:04:11.102Z"), status: "A", amount: 100 }
{ _id: 3, cust_id: "xyz1", ord_date: ISODate("2013-10-12T17:04:11.102Z"), status: "D", amount: 25 }
{ _id: 4, cust_id: "xyz1", ord_date: ISODate("2013-10-11T17:04:11.102Z"), status: "D", amount: 125 }
{ _id: 5, cust_id: "abc1", ord_date: ISODate("2013-11-12T17:04:11.102Z"), status: "A", amount: 25 }
All i want is to get the total value of key "amount", like for example-
50+100+25+125+25
You can query like this:
db.yourCollection.aggregate({ $group: { _id : null, sum : { $sum: "$amount" } } });
More details about aggregation can be found at here, and more details about sum can be found here

Can't select several rows from mongo database

I want to aggregate some rows from my mongo database. I have this table in the picture.
Sample this database:
[ { _id: 5c2857dbf45028a6280078d8,
sum: 123,
currency: 'UAH',
source: 'Видатки',
description: 'Сходив по хліба',
date: '2018-12-16' },
{ _id: 5c286449353de8149c1a0785,
sum: 101,
currency: 'EUR',
source: 'Прибутки',
date: '2018-12-17',
description: '-' },
{ _id: 5c287d0d51dcdf61f9cda68e,
sum: 14,
currency: 'UAH',
type: 'Видатки',
description: 'Сходив по хліба 2',
date: '2018-12-16',
source: '-' },
{ _id: 5c287d0d51dcdf61f9cda68f,
sum: 16,
currency: 'EUR',
type: 'Прибутки',
date: '2018-12-17',
description: 'Транспорт',
source: 'Видатки' },
{ _id: 5c324f2a1596d0471c379fa6,
sum: '200',
currency: 'USD',
source: 'Видатки',
description: 'Ремонт',
date: '2019-01-01' }
]
I trying to change $or expression on $and, but its not working
db.collection('operations').aggregate([
{
$match: { $or: [ { $and: [ {sum: { $gt: 100}}, {currency: {$eq: "EUR"} } ] }, { $and: [ {sum: { $gt: 150}}, {currency: {$eq: "USD"} } ] } ] }
}
], callback);
I expected to select operations where i have sum > 100 in EUR currency and rows with USD with sum > 150. But i have only rows with sum > 100 in EUR.
Bro,
Your sum is string
_id: 5c324f2a1596d0471c379fa6,
sum: '200',
currency: 'USD',
source: 'Видатки',
description: 'Ремонт',
date: '2019-01-01' }

Object access via Angular

I want to acccess the fields category and specCategory. I applied *ngFor="let x of data" {{x._id.category}} but it is not working. Whats wrong with it?
I am using aggregate functionality to group the categories.
$group: {
_id: {
category: "$category",
specCategory: "$specCategory"
},
min: {$min: '$price'},
max: {$max: 500},
total:{$sum:1}
}
Result:
[ { _id: { category: 'Wasser & Wind', specCategory: 'Surfen' }, min: 49, max: 500, total: 1 }, { _id: { category: 'Reisen', specCategory: 'Hotel' }, min: 49, max: 500, total: 1 } ]
I will need to access the category, specCategory and total value
you miss closing curly brackets.
{ _id: { category: 'Reisen', specCategory: 'Hotel' },
should be
{ _id: { category: 'Reisen', specCategory: 'Hotel' }},
I added plunker take a look on file: app/app.component.ts

Categories