mongodb mapreduce script to count total orders fails - javascript

I'm new to mongodb and I'm planning to migrate from SQL to noSQL. I've a lot of stored procs and I think mapReduce is the "equivalent" in noSQL world.
I've started with a js script that tries to count orders by customer, but it gives wrong result.
The script is:
db = connect("localhost:27017/pgi");
for(i=0;i<1000;i++){
db.orders.insert(
{
"cust_id" : 1,
"total" : 100,
});
}
for(i=0;i<1000;i++){
db.orders.insert(
{
"cust_id" : 2,
"total" : 100,
});
}
var res = db.orders.find({cust_id : 1});
print("Total Orders for customer 1:" + res.count());
var res = db.orders.find({cust_id : 2});
print("Total Orders for customer 2:" + res.count());
//map reduce
var map = function(){
emit(this.cust_id, 1);
}
var reduce = function(key, values){
var c = 0;
for (index in values) {
c += 1;
}
return {cust_id : key, count: c};
}
var res = db.orders.mapReduce(
map,
reduce,
{
out : {inline : 1}
}
);
res.find({}).forEach(function(item){
printjson(item);
});
the expected output is 1000 for each customer but I'm getting this:
connecting to: test
connecting to: localhost:27017/pgi
Total Orders for customer 1:1000
Total Orders for customer 2:1000
{ "_id" : 1, "value" : { "cust_id" : 1, "count" : 101 } }
{ "_id" : 2, "value" : { "cust_id" : 2, "count" : 101 } }
Could someone kindly tell me what was wrong.
Regards,

Using MapReduce it's essential that the reducer output is of the same format as the mapper output value as the reducer may run multiple times for the same key. Also, the reducer does not need to output the key, only the resulting value after performing whatever operations are required on the input array.
So in your case the mapper looks correct for counting orders by customer, but the reducer should just output the total count rather than generating an Object with the key and count.
Also the reducer needs to sum the value of each index, not increment by 1, to handle the case where it is operating on the output of previous invocations of the reduce function.
var reduce = function(key, values){
var c = 0;
for (var index in values) {
c += values[index];
}
return c;
}

Related

How do I get items from localStorage?

In my app I've got 2 functions to work with localStorage.
When I add the first and second items, it works properly, but when it is the third item, it gives an error.
Here are the functions:
w.getLocalStorage = function() {
var c = localStorage.getItem('cities');
var arr = [];
arr.push(c);
return c ? arr : [];
}
w.setLocalStorage = function(data, googleData, cities, name) {
if (data) {
city.name = data.name;
city.coord.lat = data.coord.lat;
city.coord.lon = data.coord.lon;
cities.push(JSON.stringify(city));
// console.log(city);
localStorage.setItem("cities", cities);
} else if (googleData) {
city.name = name;
city.coord.lat = googleData.results[0].geometry.location.lat;
city.coord.lon = googleData.results[0].geometry.location.lng;
console.log('cities', cities);
cities.push(JSON.stringify(city));
// console.log(cities, city);
localStorage.setItem("cities", cities);
}
}
Here is what it returns for the first 2 items:
Array[1]
0 : "{"name":"Pushcha-Voditsa","coord":{"lat":50.45,"lon":30.5}}"
1 : "{"name":"Kyiv","coord":{"lat":50.4501,"lon":30.5234}}"
Here is what when the third items is added:
Array[1]
0 : "{"name":"Pushcha-Voditsa","coord":{"lat":50.45,"lon":30.5}}, {"name":"Kyiv","coord":{"lat":50.4501,"lon":30.5234}}"
1 : "{"name":"Kyiv","coord":{"lat":50.4501,"lon":30.5234}}"
How can I fix this?
As you can only store string in localStorage, to persist object convert them in stringified format using JSON.stringify() method and on retrieval use JSON.parse() to parses the JSON string to construct the JavaScript value or object.
Here are the code snippet, which require attention. You should persist stringified cities data
cities.push(city);
localStorage.setItem("cities", JSON.stringify(cities));
While retrieval, parse it JavaScript object
var cities = localStorage.getItem('cities');
var c = cities ? JSON.parse(cities) || [];

How to update multiple collection keys received as arguments?

I'm trying to increase different values in my collection using the same code.
I'm trying to compute that in a function where the updated properties will depend on the parameters:
BuyEntitee : function(id_fb,entitee)
{
var j = Joueur.findOne({id_fb:id_fb});
var prix_current = j["prix_"+entitee];
var update_query = {};
update_query[entitee+"s"] = j[entitee+"s"] + 1;
update_query["prix_"+entitee] = Math.round(50*Math.pow(1.1,j[entitee+"s"]));
Joueur.update( {id_fb:id_fb}, {
$set: {update_query}
}
);
j = Joueur.findOne({id_fb:id_fb}); // on recharge le jouer ... utile ??
console.log('nbHumains : ' + j.humains+ ' query = '+JSON.stringify(update_query));
return j.rochers;
}
But unfortunately, the query is 1 level too deep in the structure :
meteor:PRIMARY> db.joueur.findOne()
{
"_id" :
"humains" : 12,
"prix_humain" : 50,
"update_query" :
{
"humains" : 13,
"prix_humain" : 157
}
}
I'm creating the update_query object so that I can programmatically change the parameters in the update function (saw this here).
Is there a way to perform that?
What happened is, in fact, a result of the ES6 syntactic sugar for specifying objects.
When you specified {update_query}, it was interpreted as an object with the key of "update_query" and the value of the variable update_query.
Therefore, it is the equivalent of:
Joueur.update( {id_fb:id_fb}, {
$set: {
update_query: update_query
}
}
);
What you really want is to assign the update_query itself to the $set key:
Joueur.update( {id_fb:id_fb}, {
$set: update_query
}
);
On a side note, you probably want to use the $inc modifier in order to increment the entitee+"s" by 1.

Issue Pushing values in to objects Javascript

Have some issue with push the values in to the javascript array object. Please any one give me the perfect solution
Class code :
var myfuns = ( function(undefined) {
var myarr ={};
function _add(arrayparam){
if (myarr.current == undefined) {
myarr.current = [];
myarr.current.push(options.current_info);
}else{
}
}
function _getList() {
return $.extend(true, {}, myarr);
}
return {
add : _add,
getList : _getList
}
}());
Here am calling and manage the values and keys
function setmydetails(){
var my_param = {
current_info : {
pg : '#tset',
no : 12,
name : "john",
row : 0,
},
userprofile : [],
class : [],
marks : [],
games : []
};
myfuns.add(my_param);
}
Now i got the array
myfuns.getList() // GOT proper array what i passed in my_param
Question : How to modify the existing values from any one of the Inner array from the myarr Obj
Ex: Once First array created later have to modify some from "myarr.current" = > Change current_info.row to 2222
Similar i have to add some array in to " myarr.class " etc
I would like to say try this one not tested
function _add(arrayparam){
if (myarr.current == undefined) {
myarr.current = [];
myarr.current.push(options.current_info);
}else{
$.extend( myarr.current, arrayparam);
}
}
proper source : https://api.jquery.com/jquery.extend/

how to increase custom count in jquery json

If laptop model and serial id are same, i've to add new field totalModel and increase count. For example in below case: serialid "1" and laptop model "xyz" are coming two time so i want to add "totalModel" count as 2 and so on. How can i achieve this in jquery
This question is not really about jQuery, it is about mapping and filtering arrays and objects. However, we can use some jQuery convenience methods to solve it.
A large part of solving these problems is by properly defining what you want to do. It sounds from your question that you want to get a map of unique serial ids per laptop model type. We can use JavaScript's Array.prototype.reduce to produce just such a map (Note that we will take the 'sold' value for the first of each laptop model we encounter):
var laptop_models = data.reduce(function (memo, obj) {
if (!memo[obj.laptopModel]) {
memo[obj.laptopModel] = {
unique_serial_ids: [],
sold: obj.sold
};
}
if ($.inArray(obj.serialid, memo[obj.laptopModel].unique_serial_ids) === -1) {
memo[obj.laptopModel].unique_serial_ids.push(obj.serialid);
}
return memo;
}, {});
Next, we can map our laptop_models object into the array you specified as your expected result:
var result = $.map(laptop_models, function (laptop_model, model_name) {
return {
laptopModel: model_name,
totalModel: laptop_model.unique_serial_ids.length,
sold: laptop_model.sold
};
});
You got the idea already. Iterate through the array.
if them item is in a hash, increment the count, otherwise, add to the hash and set the count to 1
var hash = {};
for (var i = 0;i<data.length;i++) {
if (hash[data[i].laptopModel) {
hash[data[i].laptopModel]++;
}
else
hash[data[i].laptopModel] = 1;
}
var data = [
{
"serialid": 1,
"laptopModel": "xyz",
"sold": "yes",
"cnt": 5
},
{
"serialid" :1,
"laptopModel": "xyz",
"sold": "yes",
"cnt": 4
},
{
"serialid": 1,
"laptopModel": "abc",
"sold": "yes",
"cnt": 3
},
{
"serialid": 3,
"laptopModel": "xyz",
"sold": "yes",
"cnt": 2
}];
var result = []; //work if result = {};
var tempArray = []; // used to store unique name to prevent complex loop
data.forEach(function(item){
if($.inArray(item.laptopModel, tempArray)< 0){// unique name
result.push(formatData(item));
tempArray.push(item.laptopModel);
}
else{
var indexNew = $.inArray(item.laptopModel, tempArray);
result[indexNew]["totalModel"] += 1;
}
});
function formatData(item){
return{
"laptopModel": item.laptopModel,
"sold": item.sold,
"totalModel": 1
}
}
alert(JSON.stringify(result)); //expect array 2 item but it's empty array
console.log(result); //Will have result 2 item when I view console window
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Get random json object

I want to get random hotelCode (for example CUNMXSAKU but randomly) object.
Is it possible to have this object randomly in javaScript or Jquery.
My JSON:
var simulatedHotelCodes = {
"CUNMXSAKU" : {
"roomCodes" : "DEAL, JRST, JPOV, JSSW, PJRS, PJOV, PJSW, RMOV, RMOF, PRES"
},
"CUNMXMAYA" : {
"roomCodes" : "ROAI, FVAI, DXAI, CAAI, SUAI, CABA, SIGA, PRAI, POFA, ROOM, FMVW, DELX, CASA, SUIT, CASI, SIGN, PROF, PROFS"
},
"CUNMXDPAV" : {
"roomCodes" : "GDVW, MRNA, FMLY, DFAM, HNDO, OCVW, DOLP, FMOV, PCDO, HNOC, PCOV, PFOV, ROHO"
},
"CUNMXHIDD" : {
"roomCodes" : "JRST, JRSU, DOME"
},
"CUNMXDSAN" : {
"roomCodes" : "DEAL, DELX, DEXBA, DXOF, DOFB, PROV, PROF, PROB, POFC, HONY, FAMI, PRJS, DEBL, PRDD"
}
};
Output:
"CUNMXMAYA" : {
"roomCodes" : "ROAI, FVAI, DXAI, CAAI, SUAI, CABA, SIGA, PRAI, POFA, ROOM, FMVW, DELX, CASA, SUIT, CASI, SIGN, PROF, PROFS"
}
or
"CUNMXHIDD" : {
"roomCodes" : "JRST, JRSU, DOME"
}
Randomly
Thanks in advance
I'd use Object.getOwnPropertyNames() to get an array of all the properties, then pick a random index.
var simulatedHotelCodes = {
"CUNMXSAKU" : {
"roomCodes" : "DEAL, JRST, JPOV, JSSW, PJRS, PJOV, PJSW, RMOV, RMOF, PRES"
},
"CUNMXMAYA" : {
"roomCodes" : "ROAI, FVAI, DXAI, CAAI, SUAI, CABA, SIGA, PRAI, POFA, ROOM, FMVW, DELX, CASA, SUIT, CASI, SIGN, PROF, PROFS"
},
"CUNMXDPAV" : {
"roomCodes" : "GDVW, MRNA, FMLY, DFAM, HNDO, OCVW, DOLP, FMOV, PCDO, HNOC, PCOV, PFOV, ROHO"
},
"CUNMXHIDD" : {
"roomCodes" : "JRST, JRSU, DOME"
},
"CUNMXDSAN" : {
"roomCodes" : "DEAL, DELX, DEXBA, DXOF, DOFB, PROV, PROF, PROB, POFC, HONY, FAMI, PRJS, DEBL, PRDD"
}
};
var properties = Object.getOwnPropertyNames(simulatedHotelCodes);
var index = Math.floor(Math.random() * properties.length);
var output = {};
output[properties[index]] = simulatedHotelCodes[properties[index]];
console.log(output);
If you only care about modern browsers, check #dave's answer which is cleaner (and it probably has a better performance). If you want a cross-browser solution here there is an option:
// Define amount of json objects
var length = 0;
for (var key in json)
length++;
// Get random index and iterate until get it
var rnd = Math.floor(Math.random()*length),
i = 0,
obj;
for (var key in json) {
if (i == rnd) {
obj = {};
obj[key] = json[key];
break;
}
i++;
}
// obj has the random item
Note that you would need the random selected key to use obj. You could change this:
obj = {};
obj[key] = json[key];
to this:
obj = json[key];
to save only the random item value.
http://jsfiddle.net/paska/m2y7gvnp/1/
Yes it is possible. But it would be more easy if you put those object in array so that you can access those object through array index. As array index is an integer, you can randomly generate that array index and then access that object.

Categories

Resources