Mongodb: Converting numeric string to number - mongodb

How can we convert a numeric string to number in Mongodb?
Actual Problem:
Collection: try
Two Sample documents stored in try collection:
{
_id: "1"
testField: 150
}
{
_id: "A"
testField: 140
}
I want to filter out the _id field in the project phase for further processing in group phase. The query below is working fine but I need better solution for it like using type or any other method.
db.try.aggregate([{$match: {"_id":{$in:["1","2","3","4","5","6","7","8","9"]}}}, {$group:{"_id":0, total: {$sum:"$testField"}}}])

You can use regex in this case:
db.try.aggregate([{$match: {"_id":
{$in:[/\d+/]}}},
{$group:{"_id":0, total: {$sum:"$testField"}}}])

An alternative is to use MapReduce where in your map function you can check whether an _id contains a number:
Sample documents:
db.try.insert([
{
_id: "1",
testField: 150
},
{
_id: "2",
testField: 150
},
{
_id: "A",
testField: 140
},
{
_id: "B",
testField: 140
}
]);
MapReduce:
var map = function(){
var numeric_id = !isNaN(this._id) ? "numeric" : "non_numeric";
emit(numeric_id, this.testField);
};
var reduce = function(key, values) {
return Array.sum(values);
};
db.try.mapReduce(
map,
reduce,
{ out: "try_totals" }
);
Result:
db.try_totals.find()
/* 0 */
{
"_id" : "non_numeric",
"value" : 280
}
/* 1 */
{
"_id" : "numeric",
"value" : 300
}

Related

MongoQuery to update document using addition

I have the following document in student collection:
{
"uid": 1,
"eng": 70
}
Now I want to add 10 into eng field and want result 80. to do this I am using following query:
db.getCollection('student').aggregate([{$match:{uid:1}},{$set:{eng:{$sum:10}}}])
but it is not working. SO how can add any number in the field to the required output? is any addition query in MongoDB. help me here
I suggest using the $inc operator here:
db.getCollection('student').update(
{ uid: 1 },
{ $inc: { eng: 10 } }
)
SOLUTION #1: Set sum to the same field eng.
db.student.aggregate([
{ $match: { uid: 1 } },
{
$set: {
eng: { $add: ["$eng", 10] } // $sum: ["$eng", 10] Also works;)
}
}
])
Output:
{
"_id" : ObjectId("6065f94abb72032a689ed61d"),
"uid" : 1,
"eng" : 80
}
SOLUTION #2: Set sum to a different field result.
Using $addFields add result filed.
Using $add add 10 to eng and store it in result.
db.student.aggregate([
{ $match: { uid: 1 } },
{
$addFields: {
result: { $add: ["$eng", 10] }
}
}
])
Output:
{
"_id" : ObjectId("6065f94abb72032a689ed61d"),
"uid" : 1,
"eng" : 70,
"result" : 80
}

need me use aggregation mongodb in arrays

I need help in aggregate this query, I need aggregate values of debito
{
"_id" : ObjectId("5a088f6584ccb0a665900726"),
"usuario" : "tamura",
"creditos" : [
{
"nome_do_credito" : "credito inicial",
"credito" : 0
}
],
"debitos" : [
{
"nome_do_debito" : "debito inicial",
"debito" : 0
},
{
"nome_do_debito" : "Faculdade",
"debito" : "150.00"
}
]
}
I need the output
debito : 150
(0+150)
You will first need to turn all your debito fields into a numerical type (as in 150.00) since you cannot do Maths on strings (as in "150.00"). And then the following query should do the trick:
db.collection.aggregate({
$project: {
"debitos": {
$sum: "$debitos.debito"
}
}
})
In case you have more than one document in your collection and you want the total sum over all documents you can run this:
db.collection.aggregate({
$unwind: "$debitos" // flatten the "debitos" array
}, {
$group: {
"_id": null, // do not really group, just throw all documents in the same group
"debitos": {
$sum: "$debitos.debito" // sum up all debito fields
}
}
})

wrong result in MongoDB mapreduce function?

I have Collection "cars" from that want to get count of certified cars as trueCount and flaseCount where certified is boolean.
am issuing the following mapreduce query
map:-
function() { for (var idx = 0; idx < this.cars.length; idx++) {
var key = this.cars[idx].carName;
var value = {
count : 1,
certifiedCheck : this.cars[idx].certified
};
emit(key, value);
} }
reduce:-
function(key, values) {
certifiedCount = { trueCount: 0, falseCount: 0 };
values.forEach(function(value) {
if ( value.certifiedCheck )
certifiedCount.trueCount += value.count;
else
certifiedCount.falseCount += value.count;
});
return certifiedCount;
query:
{ "type": "cars" }
getting the following result :
{ "id" : "carName" , "value" : { "true" : 277.0 , "false" : NaN}};
even though I have 457 documents in the collection.
Please someone help me here to fix this issue.
Thanks in advance
You mixed up your map-reduce: to reduce to two keys "true" and "false" you need to emit these as keys. Then, the reducer will run per key.
As pseudo code:
map:
for each car
evaluate whether it should be true or false
key = (true/false)
emit(key, { count : 1 })
reduce:
(input is true/false as key, array of count-documents as value)
for each value-document
sum up the count
return key, sum
This should yields two documents with true / false as key and the respective sum as value.
You should consider using the aggregation framework for running the aggregation since it achieves the same result albeit faster than MapReduce as aggregation runs natively in the server (C++), MapReduce spawns separate javascript thread(s) to run JS code.
Thus said, if you run the following aggregation pipeline which uses the $cond operator to evaluate the counts based on the logic in the field expression, you will get a similar result:
Because you haven't showed your collection schema, I've assumed the following sample documents with a cars field as array having seen in your mapReduce you are doing a for loop on the cars property:
Populate test collection
db.collection.insert([
{ _id: 1, cars: [ { model: "A", certified: true }, { model: "B", certified: true } ] },
{ _id: 2, cars: [ { model: "A", certified: false }, { model: "B", certified: true } ] },
{ _id: 3, cars: [ { model: "A", certified: true }, { model: "B", certified: false } ] },
{ _id: 4, cars: [ { model: "A", certified: true }, { model: "B", certified: false } ] },
{ _id: 5, cars: [ { model: "A", certified: true }, { model: "B", certified: true } ] }
])
Run aggregation operation
db.collection.aggregate([
{ "$unwind": "$cars" },
{
"$group": {
"_id": "$cars.model",
"trueCount": {
"$sum": {
"$cond": [ "$cars.certified", 1, 0 ]
}
},
"falseCount": {
"$sum": {
"$cond": [ "$cars.certified", 0, 1 ]
}
}
}
}
])
Result:
/* 1 */
{
"_id" : "A",
"trueCount" : 4,
"falseCount" : 1
}
/* 2 */
{
"_id" : "B",
"trueCount" : 3,
"falseCount" : 2
}

Mongodb: find documents with array field that contains more than one SAME specified value

There is three documents in collection test:
// document 1
{
"id": 1,
"score": [3,2,5,4,5]
}
// document 2
{
"id": 2,
"score": [5,5]
}
// document 3
{
"id": 3,
"score": [5,3,3]
}
I want to fetch documents that score field contains [5,5].
query:
db.test.find( {"score": {"$all": [5,5]}} )
will return document 1, 2 and 3, but I only want to fetch document 1 and 2.
How can I do this?
After reading your problem I personally think mongodb not supported yet this kind of query. If any one knows about how to find this using mongo query they defiantly post answers here.
But I think this will possible using mongo forEach method, so below code will match your criteria
db.collectionName.find().forEach(function(myDoc) {
var scoreCounts = {};
var arr = myDoc.score;
for (var i = 0; i < arr.length; i++) {
var num = arr[i];
scoreCounts[num] = scoreCounts[num] ? scoreCounts[num] + 1 : 1;
}
if (scoreCounts[5] >= 2) { //scoreCounts[5] this find occurrence of 5
printjsononeline(myDoc);
}
});
Changed in version 2.6.
The $all is equivalent to an $and operation of the specified values; i.e. the following statement:
{ tags: { $all: [ "ssl" , "security" ] } }
is equivalent to:
{ $and: [ { tags: "ssl" }, { tags: "security" } ] }
I think you need to pass in a nested array -
So try
db.test.find( {"score": {"$all": [[5,5]]}} )
Source
Changed in version 2.6.
When passed an array of a nested array (e.g. [ [ "A" ] ] ), $all can now match documents where the field contains the nested array as an element (e.g. field: [ [ "A" ], ... ]), or the field equals the nested array (e.g. field: [ "A" ]).
http://docs.mongodb.org/manual/reference/operator/query/all/
You can do it with an aggregation. The first step can use an index on { "score" : 1 } but the rest is hard work.
db.test.aggregate([
{ "$match" : { "score" : 5 } },
{ "$unwind" : "$score" },
{ "$match" : { "score" : 5 } },
{ "$group" : { "_id" : "$_id", "sz" : { "$sum" : 1 } } }, // use $first here to include other fields in the results
{ "$match" : { "sz" : { "$gte" : 2 } } }
])

MongoDB sum() data

I am new to mongoDB and nosql, what is the syntax to get a sum?
In MySQL, I would do something like this:
SELECT SUM(amount) from my_table WHERE member_id = 61;
How would I convert that to MongoDB? Here is what I have tried:
db.bigdata.aggregate({
$group: {
_id: {
memberId: 61,
total: {$sum: "$amount"}
}
}
})
Using http://docs.mongodb.org/manual/tutorial/aggregation-zip-code-data-set/ for reference you want:
db.bigdata.aggregate(
{
$match: {
memberId: 61
}
},
{
$group: {
_id: "$memberId",
total : { $sum : "$amount" }
}
})
From the MongoDB docs:
The aggregation pipeline is a framework for data aggregation modeled on the concept of data processing pipelines. Documents enter a multi-stage pipeline that transforms the documents into an aggregated results.
It would be better to match first and then group, so that you system only perform group operation on filtered records. If you perform group operation first then system will perform group on all records and then selects the records with memberId=61.
db.bigdata.aggregate(
{ $match : {memberId : 61 } },
{ $group : { _id: "$memberId" , total : { $sum : "$amount" } } }
)
db.bigdata.aggregate(
{ $match : {memberId : 61 } },
{ $group : { _id: "$memberId" , total : { $sum : "$amount" } } }
)
would work if you are summing data which is not a part of array, if you want to sum the data present in some array in a document then use
db.collectionName.aggregate(
{$unwind:"$arrayName"}, //unwinds the array element
{
$group:{_id: "$arrayName.arrayField", //id which you want to see in the result
total: { $sum: "$arrayName.value"}} //the field of array over which you want to sum
})
and will get result like this
{
"result" : [
{
"_id" : "someFieldvalue",
"total" : someValue
},
{
"_id" : "someOtherFieldvalue",
"total" : someValue
}
],
"ok" : 1
}