global variables in javascript / mongodb / mapreduce - javascript

I know this has been asked countless times on the internet but I can't figure out what's going on here and I have been banging my head against walls for hours now.
This works :
in myscript.js :
obj = 'hello';
var f = function() {
printjson('obj=' + obj);
}
f();
$ mongo myscript.js
obj=hello
This doesn't work :
date1 = "2013-09-03T00:00:00Z";
date2 = "2013-09-04T00:00:00Z";
var mapIntensities = function() {
emit(this.unit, this.intensity);
};
var reduceIntensities = function(unit, intensities) {
return {date: date1, "unit": unit, "intensity": Array.sum(intensities)};
};
db.units.mapReduce(mapIntensities, reduceIntensities, {out: "aggregate_intensities", query: {"DATE": {$gte: ISODate(date1), $lt: ISODate(date2)}}})
Why is that ? The problem occurs in the reduce() function (if just there I replace date1 with the hardcoded value it works)
Is it specific to mongodb's way to do mapreduce ? (as the working example suggests)

Because date1 is never defined within the Map Reduce itself, it is only ever used here:
return {date: date1, "unit": unit, "intensity": Array.sum(intensities)};
And then you do not define a variable to input at all into the actual call of the Map Reduce.
The Map Reduce runs within a self contained JavaScript (spidermonkey or v8) envo within MongoDB, not in the mongo console as I assume you are doing there.
You need to use the scope param: http://docs.mongodb.org/manual/reference/command/mapReduce/#dbcmd.mapReduce to send in date1

Related

Firebase timestamp filter

I'm new to firebase, actually I'm trying to load some data based on timestamp and retrieve between two timestamp using startat and endat. Data is pushed through Python.
The data is as shown in the sample screenshot
sample data
The data path popping-fire-7751.firebaseio.com/device488
activevolt: 396
avgPowerFactor: 0.95
avgThdi: 7.5
cubetemp: 37
datetime: "2016-02-08 15:16:32"
timestamp: 1454924792
totalPowerGen: 34
I'm pushing data through python setting the priority as timestamp.
When I try to filter as shown here it returns null. But without startAt and endAt it shows all the values.
http://jsfiddle.net/casperkamal/EZUtP/64/
var startTime = 1454924792;
var endTime = 1454924798;
new Firebase("https://popping-fire-7751.firebaseio.com/")
.startAt(startTime)
.endAt(endTime)
.once('value', show);
can anybody help me on what I'm doing wrong ?
You're trying to skip a level in your JSON tree:
var startTime = 1454924792;
var endTime = 1454924798;
new Firebase("https://popping-fire-7751.firebaseio.com/")
.child('device488')
.startAt(startTime)
.endAt(endTime)
.once('value', show);
I highly recommend that you don't depend on the implicit priority anymore and instead just filter using orderByChild()
new Firebase("https://popping-fire-7751.firebaseio.com/")
.child('device488')
.orderByChild('timestamp')
.startAt(startTime)
.endAt(endTime)
.once('value', show);
You'll need to add an index to your Security Rules:
{
"rules": {
"device488": {
".indexOn": ["timestamp"]
}
}
}
But the more explicit behavior is well worth the effort of adding this.

Incrementing a date in javascript, in order to update MongoDB

In MongoDB collection I have 3 objects. I need to update one variable (date type) in each object. The main task is to increment the date of the objects. For example: all objects have the same variable:
"Time1" : ISODate("2016-01-12T21:37:46.738Z")
My problem is to update the first object with the current date, manually I do it in this way:
$db.getCollection('my.data')({'_id':ObjectId("52e637fca92cf1ec6a73c1e8")}, {$currentDate: {Time1: true}})
The next is to increase the date of the second object by 1 day, I mean to update it with tomorrow date. I couldn't do it through the shell, because $inc doesn't work with Date type.
So, I am lost with javascript
I found how to get it with java script but I don't know how to collect all if this in one script.
var tomorrow = new Date();
tomorrow.setDate(today.getDate()+1);
Thank you for your help.
You could use the $set operator for the other fields, together the the $currentDate operator all within the update object:
var tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate()+1);
var dayAfterTomorrow = new Date();
dayAfterTomorrow.setDate(dayAfterTomorrow.getDate()+2);
db.getCollection("my.data").update(
{ "_id": ObjectId("52e637fca92cf1ec6a73c1e8") },
{
"$currentDate": { "Time1": true },
"$set": {
"Time2": tomorrow,
"Time3": dayAfterTomorrow
}
}
)

MongoDB: how to update n records based on ObjectID

I've created a Collection containing 1 million documents, and I'm trying to select 50000 of these records based on the ObjectID, and update one of the values (i'm working in Mongo shell, running on Ubuntu).
Is it possible to define a 50000 document range? It doesn't matter which documents are included in the 50000 range, I simply want to ringfence a definite number of records and run an update operation using the primary id so that I can measure the performance time.
The code I've tried to run doesn't work:
use Assignment
var _start = new Date()
db.FlightsDate.update({$set:{Airtime: 8888}}).limit(50000).hint({_id:1});
var _end = new Date();
print("Time to Bulk Update AirTime key for 50000 documents… " + ((_end _start)/1000));
...i'm gathering that MongoDB needs me to include a query in the command to specify which docs are to be updated (I now understand from reading other posts that .limit won't constrain the number of records than an .update writes to).
Please can anyone advise a method that'll enable me to define the number of records to be updated?
Grateful for advice.
R,
Jon
If you are simply looking for a "range" that covers 50,000 of the documents in the collection then your best approach is to query and find the "starting" and "ending" documents of your range first. Then apply that "range" specification to your update.
var start_id = db.FlightsDate.find({}).limit(1).toArray()[0]._id;
var end_id = db.FlightsDate.find({}).skip(49999).limit(1).toArray()[0]._id;
var _start = new Date();
db.FlightsDate.update(
{ "_id": { "$gte": start_id, "$lte": end_id } },
{ "$set"; { "Airtime": 8888 } },
{ "multi": true }
);
var _end = new Date();
( _end - _start )/1000;
If you then wanted the next 50,000 in an additional range then :
var start_id = db.FlightsDate.find(
{ "_id": { "$gt": end_id } }
).limit(1).toArray()[0]._id;
var end_id = db.FlightsDate.find(
{ "_id": { "$gt": end_id } }
).skip(49999).limit(1).toArray()[0]._id;
And do it all again.
The point is you need to know where to "start" and when to "end" within a range to limit your update to just 50,000 documents without any other criteria to do so.
Also note the usage of "multi" in the update method there. By default, .update() does not "update" any more than one document, essentially being the first match. So what you mean to do is update "all documents in the range" and that is why you need to apply "multi" here.

Sorting a returned JSON array by date

Sorry if this is a really n00b question, but I am just getting into rails and can't figure this one out.
I am currently working with Analytics from a site. And want to put the data into a chart. However when I get the data back the stuff I want isn't in order. At the moment the data returned is:
{"legend_size":1,"data":{"series":["2013-06-20","2013-06-21","2013-06-22","2013-06-23","2013-06-24","2013-06-25","2013-06-26"],"values":{"undefined":{"2013-06-26":41,"2013-06-24":2,"2013-06-25":55,"2013-06-22":0,"2013-06-23":1,"2013-06-20":0,"2013-06-21":0}}}}
And what I need is the ["data"]["values"]["undefined"] bit to be ordered by date.
I know it's a simple question. But I have looked everywhere and can't figure it out.
Ok, as I said in the comment you can't really sort and object as it has an arbitrary order, so you must use an array.
My solution would be:
var objectFromAnalytics = {"2013-06-26":41,"2013-06-24":2,"2013-06-25":55,"2013-06-22":0,"2013-06-23":1,"2013-06-20":0,"2013-06-21":0},
toSort = [],
dateParts;
for (var date in objectFromAnalytics) {
dateParts = date.split("-");
toSort.push({ date: new Date(dateParts[0], (dateParts[1] - 1), dateParts[2]), value: objectFromAnalytics[date] });
}
var sorted = toSort.sort(function(a,b){
return a.date < b.date ? -1 : a.date > b.date ? 1 : 0; //you can change this to sort by value if you want
});
//sorted == [{ date: dateObject, value: value from analytics} , { ... }]
You can probably get away doing this in a few less lines, but I think is understandable this way :)

JavaScript Reformatting JSON arrays

I am relatively new to the JSON notation, and have run into an issue when attempting to reformat. The current format contained in the database needs to be modified to a new format for importation into a project timeline graph.
Here is the current JSON format:
[
{
"name":"5-HP-N/A-N/A-F8",
"node":{
"name":"5",
"id":14
},
"timeline":{
"epc":null,
"m1":null,
"m2":null,
"m3":1554087600000,
"m4":1593572400000,
"m5":1625108400000,
"m6":1641006000000,
"m7":1656644400000
},
"fab":{
"name":"F8",
"id":1
}
},
However, in order to display in the graph, I need the following format:
{
'start': new Date(value from epc, or first non-null milestone),
'end': new Date(value from m1 or first non-null milestone), // end is optional
'content': 'label from start Date milestone'
'group' : ' value from name field above 5-HP'
'classname' : ' value from start Date milestone'
});
I am trying to write a function in order to accomplish this. Only epc, m1, or m2 may have the value of null, but the condition must be checked for to determine if an event range should be created and where it should end. What would be the best way to reformat this json data (preferrably from an external json sheet)?
Edit: Thanks for all the help I see how this is working now! I believe I didn't explain very well the first time though, I actually need multiple class items per "group".
The end result is that these will display inline on a timeline graph 'group' line, and so I am trying to figure out how to create multiple new objects per array element shown above.
So technically, the first one will have start date = m3, and end date = m4. Then, the next object would have the same group as the first (5-HP...), the start date = m4, end date = m5...etc. This would continue until m7 (always an end date but never a start date) is reached.
This is why the loop is not so simple, as many conditions to check.
see a working fiddle here: http://jsfiddle.net/K37Fa/
your input-data seems to be an array, so i build a loop around that. if not just see this fiddle where the input data is a simple object: http://jsfiddle.net/K37Fa/1/
var i
, result = [],
, current
, propCounter
, content = [ { "name":"5-HP-N/A-N/A-F8", "node":{ "name":"5", "id":14 }, "timeline":{ "epc":null, "m1":null, "m2":null, "m3":1554087600000, "m4":1593572400000, "m5":1625108400000, "m6":1641006000000, "m7":1656644400000 }, "fab":{ "name":"F8", "id":1 } }],
// get the milestone in a function
getMileStone = function(obj) {
propCounter = 1;
for(propCounter = 1; propCounter <= 7; propCounter++) {
// if m1, m2 and so on exists, return that value
if(obj.timeline["m" + propCounter]) {
return {key: "m" + propCounter, value: obj.timeline["m" + propCounter]};
}
}
};
// loop over content array (seems like you have an array of objects)
for(i=0;i< content.length;i++) {
current = content[i];
firstMileStone = getMileStone(current);
result.push({
'start': new Date(current.epc || firstMileStone.value),
'end': new Date(current.m1 || firstMileStone.value),
'content': firstMileStone.key,
'group' : current.name,
'classname' : firstMileStone.value
});
}
EDIT:
getMileStone is just a helper-function, so you could just call it with whatever you want. e.g. current[i+1]:
secondMileStone = getMileStone(current[i + 1])
you should just check, if you are not already at the last element of your array. if so current[i+1] is undefined, and the helperfunction should return undefined.
you could then use as fallback the firstMileStone:
secondMileStone = getMileStone(current[i + 1]) || firstMileStone;
see the updated fiddle (including check in the getMileStone-Helperfunction): http://jsfiddle.net/K37Fa/6/

Categories

Resources