How to use a variable for mapReduce in MongoDB with NodeJS - node.js

I have a collection of events that look like
{
_id: BSONID
name: "event_name",
values: {a: 10, b: 1000, c: 50}
}
I'm trying to use mapReduce them using
map = function() {
return emit([this.name, this.values['a']], this.values['b']);
}
reduce = function(key, values) {
// stuff
}
collection.mapReduce(map, reduce, { out: { inline: 1 } }, callback);
However, I would like to be able to dynamically change which values I map against. In essence, I'd like to have
var key = 'a';
var value = 'b';
map = function ()
{
return emit([this.name, this.values[key]], this.values[value]);
}
The problem is that the execution context isn't passed to mongodb. Any solution that doesn't rely on using string for functions?

Yes, you can pass a "scope" variable to MapReduce:
scope = {key : "a", value : "b"};
collection.mapReduce(map, reduce, {scope : scope, out: { inline: 1 } }, callback);

Related

I want to acess the value of this json object without using the key name

{
"callExpDateMap": {
"2020-03-06:2": {
"305.0": [
{
"putCall": "CALL,
}
]
}
}
}
So this is my json object.And As you can see in "callExpDateMap",there is a date("2020-03-06:2" and then there is a value("305.0").The date("2020-03-06:2") and price("305.0") values will not be the same in every response.So If I want to access the value of "putCall" (Please remember that I can't use the key of the date and the price because it keeps changing in every response), How can I do this?...I'm using nodejs.
You need to pass this JSON to a function and call that function recursively with each inner object (or value of JSON key) and when value is string just print it or use in your way.
forEach(Object.keys(jsonobj))
function myfunc(key){
if((typeof jsonobj[key])==object){
forEach(Object.keys(jsonobj[key]));
}else{
console.log(jsonobj[key])
}
}
}
You could loop over the object and get the value,
Example:
let test = {
callExpDateMap: {
"2020-03-06:2": {
"305.0": [
{
putCall: "CALL"
}
]
}
}
};
let callExpDateMap = test.callExpDateMap;
for(const dateValue in callExpDateMap) {
for(const put in callExpDateMap[dateValue]) {
console.log(callExpDateMap[dateValue][put][0]['putCall']);
}
}
or you could use Object.keys to get the value. it's simpler then the previous approach;
let obj = {
callExpDateMap: {
"2020-03-06:2": {
"305.0": [
{
putCall: "CALL"
}
]
}
}
};
let callExpDateMap = obj.callExpDateMap;
let dateKey = Object.keys(callExpDateMap);
let price = Object.keys(callExpDateMap[dateKey]);
let putCall = callExpDateMap[dateKey][price];
console.log(putCall);

couchDb map/reduce min&max + other data

I have a document list that consists of:
time
sessionId
appv
museum
I would like to use the couchDB map/reduce function to get the result:
key : sessionId, value : {begin : time, end: time, appv : appv, museum : museum}
for the begin value: the minimum time value.
for the end value: the maximum time value
Currently I can have the minimum and maximum value with this code:
MAP :
function(doc) {
if(doc.sessionId) {
emit(doc.sessionId, [doc.time])
}
}
REDUCE :
function(keys, values, rereduce) {
if (rereduce) {
return {
'min': values.reduce(function(a, b) { return Math.min(a, b.min) }, Infinity),
'max': values.reduce(function(a, b) { return Math.max(a, b.max) }, -Infinity),
}
} else {
return {
'min': Math.min.apply(null, values),
'max': Math.max.apply(null, values),
}
}
}
RESULT :
{"rows":[
{"key":"fromDev1548326238156","value":{"min":2,"max":999}}
]}
And when I use this map function:
function(doc) {
if(doc.sessionId) {
emit(doc.sessionId, [doc.time, doc.museum, doc.appv])
}
}
I can't find the reduce function that allows me to get the result I want
Can you help me?

Deeply nested data objects in multidimensional object

I have a multidimensional object and using Vue, I am trying to make the inner object reactive.
My object looks like this:
data() {
return {
myObject: {}
}
}
And the filled data looks like this:
myObject: {
1: { // (client)
0: "X", // (index) : (value)
1: "Y"
},
2: {
0: "A",
2: "B"
}
}
If I try using:
let value = "X";
let client = 1;
let index = 1;
let obj = {};
obj[client][index] = value;
this.myObject = Object.assign({}, this.myObject, obj);
It throws an error:
TypeError: Cannot set property '0' of undefined
And if I try below, it overwrites the initial values as it is initially setting the object to {}
let obj = {};
obj[index] = value;
let parentObj = {};
parentObj[client] = obj;
this.myObject = Object.assign({}, this.myObject, parentObj);
What is the proper way of adding the values to the multidimensional object?
In javascript, dim2Thing[1][1] = ... expressions require dim2Thing[1] to exist. This is why you get the error you mentioned. So you can do two expressions, which should work fine:
dim2Thing[1] = dim2Thing[1] || {}
dim2Thing[1][1] = otherThing
For the last block, you mention that it "overwrites the initial values"
I think what's actually happening here is just that Object.assign is not recursive. It only merges top-level keys. So if parentObj has a key that over-laps with this.myObj, then sub-keys will be lost.
Object.assign({ a: { b: 2} }, { a: { c: 3 } }) // returns { a: { c: 3 } }
This is what I interpret your code as trying to do - though I am unfamiliar with vue.js at this time, so I cannot assure it will have the desired result to your webpage:
let value = "X";
let client = 1;
let index = 1;
const newObj = Object.assign({}, this.myObject);
// if you have lodash _.set is handy
newObj[client] = newObj[client] || {}; // whatever was there, or a new object
newObj[client][index] = value
this.myObject = newObj
Just use an array, thats reactive by design.
If you need to get elements from the array in your template or anywhere just add a find method
// temp
late
<div v-for="(value, idx) in myArray">{{find(obj => obj.id === idx)}}</div>
methods: {
find (searchFunction) {
return this.myArray.find(searchFunction)
}
}

RxJs getValue for nested BehaviorSubject object

I'm working with angular 4 and RxJS 5, I have an object with the following structure (with nested subjects, in this example only 2 levels):
objs = BehaviorSubject<MyObj[]>;
MyObj = {
prop1: BehaviorSubject<string> = "prop1";
prop2: BehaviorSubject<string> = "prop2";
prop1.subscribe(newValue => prop2 = prop1);
}
So if I try to output the value of objs I got something like the following:
console.log(objs.value) =>
[
{
prop1: BehaviorSubject<string>;
prop2: BehaviorSubject<string>;
},
{
...
}]
so the result doesn't include the values of prop1 and prop2 but I still have BehaviorSubject at the second level.
Is there a way to get the nested objs value like the following?:
objs = [{
prop1: "prop1";
prop2: "prop2"
}, {...}]
I'm wondering if there's a sort of the knockout ko.toJSON (http://knockoutjs.com/documentation/plugins-mapping.html)
Do you think it is generally a bad practice to have nested BehaviorSubjects or people do it everyday :)?
No, there is nothing builtin that does that. You could certainly roll your own method. This might be something you can start with:
function isPrimitive(obj: any) {
return obj !== Object(obj);
}
function desubjectify(obj: any) {
if(isPrimitive(obj)) {
return obj;
}
if(obj instanceof BehaviorSubject) {
return desubjectify(obj.value);
}
let transformed: any = {};
for(let key of Object.keys(obj).filter(key => !key.startsWith('_'))) {
let value = obj[key];
if(value instanceof BehaviorSubject) {
transformed[key] = desubjectify(value.value);
} else {
transformed[key] = desubjectify(value);
}
}
return transformed;
}
Nested behavior subjects seems fishy to me but I wouldn't rule it out immediately with out knowing more details. However, I would recommend you find a good tutorial on ngrx/store and read it. Anytime people start to work a lot with behavior subjects I would recommend this.

How can I merge viewModel.items with serverItems via knockout mapping plugin?

This code does not work:
var mappingOption = {
key: function (data) {
return ko.utils.unwrapObservable(data.id);
}
ko.mapping.fromJS(serverItems, mappingOption, viewModel.items);
I want to UNION of both items (viewModel.items and serverItems)
var ClassA = new function(data) {
ko.mapping.fromJS(data, {
key: function (item) {
return ko.utils.unwrapObservable(item.id);
},
'items': {
create: function (itemData) {
return new ClassB(itemData.data);
}
}
}, self);
}
var ClassB = new function(data) {
ko.mapping.fromJS(data, {
key: function(item) {
return ko.utils.unwrapObservable(item.id);
};
), self);
}
So ClassA has a collection of ClassB. On creation, it calls the mapping function, which has a create call back on a collection of items (of type ClassB) which calls the create class B constructor, passing in the relevant data.
ClassB then takes the data from the constructor, and merges it into itself.
I'm pretty sure this will work due to the key mapping of ClassB. But haven't got the time to test it ;-)

Resources