MongoDB Map/Reduce only working in inline-mode - mongodb

I wrote map/reduce/finalize function which are working fine during my tests with the out: {inline: true} option.
But if I try to save the result in a collection using out: {replace: 'test'} (or merge, ..) it won't show me the same result.
Does anyone has a clue, what I am doing wrong?
Thx
Inline:
db.runCommand({mapreduce: 'source', map: map_deliverstat, reduce: reduce_deliverstat, finalize: finalize_deliverstat, out: {inline:1}})
{
"_id": {
"date": ISODate("2012-03-13T00:00:00Z"),
"customerid": 469
},
"value": {
"date": ISODate("2012-03-13T00:00:00Z"),
"customerid": NumberLong(469),
"sum": 294,
"nomarker": 42,
"marker": 252,
"product1": 34,
"product2": 22,
"product3": 20,
"product4": 19,
"product5": 16
}
}
Replace:
db.runCommand({mapreduce: 'source', map: map_deliverstat, reduce: reduce_deliverstat, out: {replace: 'test'}, finalize: finalize_deliverstat})
{
"_id": {
"date": ISODate("2012-03-13T00:00:00Z"),
"customerid": 469
},
"value": {
"date": ISODate("2012-03-13T00:00:00Z"),
"customerid": NumberLong(469),
"sum": 2,
"nomarker": 0,
"marker": 2,
"product1": 0,
"product2": 0,
"product3": 0,
"product4": 0,
"product5": 0
}
}

another way of running map reduce, modify as per your need and see if this works for you
The following query counts the number of customers group by state
map = function() {
emit({state: this.CustomerState}, {count:1})
}
reduce = function(key, values) {
var count = 0;
values.forEach(function(v) {
count += v['count'];
});
return {state: key,count: count};
}
db.createCollection('map_temp')
db.customer_info.mapReduce(map, reduce, {out:'map_temp'})
You will have the result saved in map_temp collection

Related

How do I update the value in the object in array (with nextjs api in mongodb database)

my database is as below
"_id":"xxxxxx",
"owner": "yyy#hotmail.com",
"products": [
{
"name": "name",
"pid": 41,
"qty": 3
},
{
"name": "name2",
"pid": 42,
"qty": 4
}],
How can I change the qty value in products with pid value 41 in the nextjs api ?
api/cart
if(method === "PUT") {
try {
const updateResult = await DbScart.findOneAndUpdate(
???
)
res.status(201).json({ success: true, data: updtprod });
} catch(err) {}
}
One option is to use update with $[<identifier>]:
{products: {$elemMatch: {pid: 41}}},
{$set: {"products.$[item].qty": newValue}},
{arrayFilters: [{"item.pid": 41}]}
See how it works on the playground example

mongodb sum aggregation return float instead of integer

I have a document which history embedded field is as below:
first_pn_data = {'_cls': 'InstallationEmbeddedHistory',
'coverage': 0.8197712971965834,
'date': datetime.datetime(2020, 9, 7, 0, 0),
'estimated_installs': 39349022,
'popularity_rank': 0,
'rank': 1851}
second_pn_data = {'_cls': 'InstallationEmbeddedHistory',
'coverage': 0.8197712971965834,
'date': datetime.datetime(2020, 9, 7, 0, 0),
'estimated_installs': 23412618,
'popularity_rank': 0,}
The estimated_installs field is an integer.
when I run the following query:
query = [
{
"$match": {
"package_name": {
"$in": ["first_pn", "second_pn"]
}
}
},
{
"$unwind": "$history"
},
{
"$group": {
"_id": "$history.date",
"total": {
"$sum": "$history.estimated_installs"
}
}
}
]
the result for the above date is:
{'_id': datetime.datetime(2020, 9, 7, 0, 0), 'total': 62761640.54968266}
while I expect the total=62761640.
I don't know why the result is float and has a decimal.
Can someone help me with this?

Sum operation on documents with different structures

I'm trying to use the aggregation pipeline to be able to do a report table with (sort,paging, etc) using mongodb for my back end. I run into a problem that my schema is not the same but i need to add all the values. I was trying to use the unwind command but it only works in arrays so run out of alternatives.
Sample Documents
{
"_id": "first",
"apple": 6,
"pears": 7,
"total_fruits": "13"
},
{
"_id": "second",
"apple": 6,
"bananas": 2,
"total_fruits": "8"
}
Desired Result
{
"_id": "result",
"apple": 12,
"pears": 7,
"bananas": 2,
"total_fruits": "21"
}
Instead of aggregating, why not use mapReduce()?
function sumKeyFromCollection(collectionName, keyName) {
map = function() { emit(keyName, this[keyName]); }
red = function(k, v) {
var i, sum = 0;
for (i in v) {
sum += v[i];
}
return sum;
}
return db[collectionName].mapReduce(map, red, {out : {inline: 1}});
}
For your example documents:
{
"_id": "first",
"apple": 6,
"pears": 7,
"total_fruits": "13"
},
{
"_id": "second",
"apple": 6,
"bananas": 2,
"total_fruits": "8"
}
You could call the function on each field name:
console.log(sumKeyFromCollection("collectionName", "apple"));
> { "_id": "...", "apple": 12 }
Then use each of them to produce your resultant document:
var fruits = [ "apple", "bananas", "total_fruits" ];
var results = [];
for (var i = 0; i < fruits.length; i++) {
results.push(sumKeyFromCollection("collectionName", fruits[i]));
}
EDIT Also, to get every field name in a collection programmatically:
function getAllCollectionFieldNames(collectionName) {
mr = db.runCommand({
"mapreduce" : collectionName,
"map" : function() {
for (var key in this) { emit(key, null); }
},
"reduce" : function(key, stuff) { return null; },
"out": "my_collection" + "_keys"
});
db[mr.result].distinct("_id");
}
Which returns an array of unique field names (even if they only appear in one document).

In meteorjs with mongodb how do I set a var in an nested array

How do I change the ans to other int and increase retry by 1 in courseList.quizScore on an update statement in mongodb with meteorjs?
Below is my query which is not working I am using $set, is this the correct operate to use? Can i use $set and $inc in the one update statement?
collection.jsx
Meteor.users.update({
_id: Meteor.userId(),
"courseList.courseId": courseId,
"courseList.quizScore.qnNum": qnNum,
}, {
$set: {
"courseList.quizScore.$.ans": selectedAns
}
})
mongoDB
{
"_id": "yo8Mi2jKtoNSzgLDL",
"courseList": [
{
"courseId": "nJmu5HW7g3wjWo47P",
"classId": "3RniSRC3NurDRwZ2x",
"quizScore": [
{
"qnNum": 0,
"ans": 0,
"retry": 1
},
{
"qnNum": 1,
"ans": 0,
"retry": 1
}
],
"status": "Not Started"
},
{
"courseId": "5ge2grte3wjWo4rh",
"classId": "bffbeRC3NurDRtbf",
"quizScore": [
{
"qnNum": 0,
"ans": 1,
"retry": 1
},
{
"qnNum": 1,
"ans": 2,
"retry": 3
}
],
"status": "Not Started"
}
]
}
There is an array within an array in your data, there is no easy way to reference the nested sub-array quizScore unless you know the position in this sub-array you want to update.
You can access the outer array courseList through $, and to access the inner array quizScore through position. Here is one sample code to update the first element of quizeScore matching courseId through using $set and $inc in one update statement.
Meteor.users.update(
{_id: Meteor.userId(),
'courseList.courseId': courseId},
{$set: {'courseList.$.quizScore.0.ans': selectedAns},
$inc: {'courseList.$.quizScore.0.retry': 1}
});

Mongoose find by value in array of key value pairs

I am trying to find a document from the structure
"brandcredits": [
{
"brand_id": "5586da128a60ebcb7abeb732",
"brand_credits": 123,
"_id": "558ce2af106319b412e48b6c"
},
{
"brand_id": "5586da238a60ebcb7abeb733",
"brand_credits": 500,
"_id": "558ce2af106319b412e48b6b"
},
{
"brand_id": "558b382e7881f424154d6c27",
"brand_credits": 500,
"_id": "558ce2af106319b412e48b6a"
},
{
"brand_id": "558b38467881f424154d6c28",
"brand_credits": 500,
"_id": "558ce2af106319b412e48b69"
},
{
"brand_id": "558b38687881f424154d6c29",
"brand_credits": 245,
"_id": "558ce2af106319b412e48b68"
}
]
My mongoose query is
BrandInfo.find({'_id':{$in: user[0].brandcredits.brand_id}},function(err,active){
console.log(active);
});
Which returns undefined
I need to query a schema with the array of brand_id.
How do I do that?
Any help would be much appreciated.
Thanks
What you're doing is searching for _id in user[0].brandcredits.brand_id which doesn't work, or even make sense because user[0].brandcredits.brand_id itself is just another ObjectID.
What you need to be searching for is: brand_id in user[0].brandcredits
So try this:
BrandInfo.find( { 'brand_id': {$in: user[0].brandcredits} } , function(err, active){
console.log(active);
});