I use MongoDB version 2.6.10. Below is the collection structure. I use MapReduce function to group the names of the user based on (created(excluding seconds), event_name.
{
"_id" : ObjectId("59c11d79078dc54153c36ee8"),
"event_name" : "notification",
"created" : ISODate("2017-09-19T13:36:57.252Z"),
"sender_name" : "nathan",
"user_name": "Ragul"",
}
{
"_id" : ObjectId("59c11d79078dc54153c36eeb"),
"event_name" : "notification",
"created" : ISODate("2017-09-19T13:36:57.772Z"),
"sender_name" : "parmesh",
"user_name": "Ram",
}
{
"_id" : ObjectId("59c11d7a078dc54153c36ef0"),
"event_name" : "notification",
"created" : ISODate("2017-09-19T13:36:58.554Z"),
"sender_name" : "nathan",
"user_name": "Ram",
}
{
"_id" : ObjectId("59c11d7a078dc54153c36ef1"),
"event_name" : "message",
"created" : ISODate("2017-09-19T13:36:58.577Z"),
"sender_name" : "nathan",
"user_name": "Ragul"",
}
Below is my query using MapReduce function. My question is whether we can use calculated date as a mapper. Help me with your suggestions
var mapfn = function(){
if (this.event_name == "message"){
name = this.recipient_name
}
else if ((this.event_name == "notification") && (this.other_status == true)){
name = this.sender_name
}
else if ((this.event_name == "notification") && (this.other_status == false)){
name = "You"
}
this.cre = {$subtract:[this.created,{$add:[{$multiply:[{$second:this.created},1000]},{$millisecond:this.created}]}]}
emit({"event_name": this.event_name, "created": this.cre}, name)
}
var redfun = function(key, value){
return Array.append(value)
}
db.getCollection('users').mapReduce(mapfn, redfun, {out: "example"}).find()
Here instead calculating the date using MongoDB expression, I tried to use javascript to eliminate the seconds and then I mapped then its worked.
var mapfn = function(){
if (this.event_name == "message"){
name = this.recipient_name
}
else if ((this.event_name == "notification") && (this.other_status == true)){
name = this.sender_name
}
else if ((this.event_name == "notification") && (this.other_status == false)){
name = "You"
}
this.created.setSeconds(0);
this.created.setMilliseconds(0);
emit({"event_name": this.event_name, "created": this.created}, name)
}
var redfun = function(key, value){
var names = value.join(",")
return names
}
db.users.mapReduce(mapfn, redfun, {out: "example"}).find()
Related
I want to write a put method in express for a nested document in mongoose.
I cannot access the id for the nested document.
{ "_id" : ObjectId("5b8d1ecbb745685c31ad8603"),
"name" : "abc",
"email" : "abc#gmail.com",
"projectDetails" : [
{
"technologies" : [
"abc",
"abc"
],
"_id" : ObjectId("5b8d1ecbb745685c31ad8604"),
"projectName" : "abc",
"projectDescription" : "abc",
"manager" : "abc",
"mentor" : "abc"
}
],
"__v" : 0
}
I am trying to access the id ("5b8d1ecbb745685c31ad8604") so that I can update the projectName.
I cannot think of how to write a put method for the same. Please help! Thanks in advance!!
You can use model.findOne() and then save() th update the document instead of model.findOneAndUpdate().
var projectId = "5b8d1ecbb745685c31ad8604";
var newProjectName = "def";
model.findOne({'projectDetails._id': projectId}, (err, data) => {
if (data) {
data.projectDetails.forEach((project) => {
if (project._id == projectId) {
project.projectName = newProjectName;
}
});
data.save();
} else {
// throw error message
}
})
app.put('/api/project/:id',(request,response)=>{
const projectId = request.params.id;
const projectName = "test";
db.users.update({"projectDetails._id":projectId},{$set:{"projectDetails.$.projectName":projectName}},function(err,data){
if(data){
}else{
}
})})
Instead of forEach try above query
i'm building an ag-Grid in Vue.js . I'm trying to set colDefs and dataRow dinamically, and all is ok but i've "actualComparator is not a function" error when i set a date filter.
coldefs are dinamics and i receive from json
colDefs:[
{
"field" : "field1",
"filter" : "text",
"headerName" : "Name",
"width" : 100},
{
"field" : "filed2",
"filter" : "text",
"headerName" : "Surname",
"width" : 80},
{
"field" : "date1",
"filter" : "agDateColumnFilter",
"filterParams" : {
"clearButton" : true,
"comparator" : "dateFilterComparator"
},
"headerName" : "Birth",
"width" : 150
}]
dateFieldComparator is a function inside the methods
dateFilterComparator(filterLocalDateAtMidnight, cellValue){
console.log("I'm here");
var dateAsString = cellValue;
if (dateAsString == null) return -1;
var dateParts = dateAsString.split("/");
var cellDate = new Date(Number(dateParts[2]), Number(dateParts[1]) - 1, Number(dateParts[0]));
if (filterLocalDateAtMidnight == cellDate) {
return 0;
}
else if (cellDate < filterLocalDateAtMidnight) {
return -1;
} else {
return 1;
}
}
The request for the json (dataRow + colDefs) is send on the beforeMount eventhook, ag-grid is showed correctly but when i try to set a filter on the date i receive the error above.
The Clear Filter button is showed but the comparator seems not initialized with my function dataParamComparator.
I've try to call the gridOptions.api.setColumnDefs() on the onReady but without success.
Regards
Davide
I am trying to compare dates in '$where' query to filter data. My 'where' query looks something like this:
function () {
var messageStatusInfoList = this.messageStatusInfoList
var startDate = someDate;
var result = false;
for (var counter = 0; counter < messageStatusInfoList.length; counter++) {
var currentMessageStatusInfo = messageStatusInfoList[counter]
if (counter > 0 && (currentMessageStatusInfo.messageStatus == "RESPONDED" )) {
var responseDate = currentMessageStatusInfo.effectiveDate
if(+responseDate >= +startDate) {
result = true;
break;
}
}
}
return result;
}
Here is sample input document:
{
"_id" : NumberLong(3687),
"messageStatusInfoList" : [
{
"effectiveDate" : ISODate("2014-08-01T13:29:26.456Z"),
"expirationDate" : ISODate("2014-08-04T11:40:29.824Z"),
"messageStatus" : "OPENED"
},
{
"effectiveDate" : ISODate("2014-08-04T11:40:29.824Z"),
"expirationDate" : ISODate("2014-08-05T13:01:00.135Z"),
"messageStatus" : "RESPONDED",
"userId" : NumberLong(8)
},
{
"effectiveDate" : ISODate("2014-08-05T13:01:00.135Z"),
"messageStatus" : "REPLY_TO_CUSTOMER",
"userId" : NumberLong(8)
}
],
"tenantId" : NumberLong(4),
"text" : "some text ..",
"version" : NumberLong(12)
}
As per the above document and given where query, if startDate is set to 2014-08-03, then the date comparison should evaluate to true(because responseDate is 2014-08-04T11:40:29.824Z and responseDate is greater than startDate). But it is not happening so. The comparison operator evaluates to false.
The issue was due to improper initialization of variable startDate in my where query.
I had data structure in MongoDB as below
{
"_id" : ObjectId("523aab00045624a385e5f549"),
"name" : "English Book 29",
"SKU" : 1000549081,
"price" : 249000,
"image" : null,
"category_id" : ObjectId("523a7802b50418baf38b4575"),
"category_name" : "English Book",
"details" : {
"Title" : "Title 549081",
"Binding" : 1,
"Author" : "Author 0",
"Publication data" : 0.5263832447608386,
"Publisher name" : "Publisher name 14",
"Number of page" : 90
}
}
Binding of book has 2 values:
0 that means soft binding, and 1 that means hard binding. I write Map Reduce to statistics for each values.
var map = function()
{
for(var key in this.details)
{
if(key == 'Binding')
{
emit({name: key}, {
'data':
[
{
name: this.details[key],
count: 1
}
]
});
}
}
};
var reduce = function (key, values) {
var reduced = {};
for(var i in values)
{
var inter = values[i];
for(var j in inter.data)
{
if(typeof(reduced[inter.data[j].name]) != "undefined")
{
reduced[inter.data[j].name] += inter.data[j].count;
}
else
{
reduced[inter.data[j].name] = 1;
}
}
}
return reduced;
};
When I run with small data (50 records) result return exactly. But when I run it with real data (192000 records) result return Not exactly. The result as below
{
"_id" : {
"name" : "Binding"
},
"value" : {
"0" : 50,
"1" : 50
}
}
I checked return data when Map/Reduce done, result as below
"counts" : {
"input" : 192000,
"emit" : 192000,
"reduce" : 1920,
"output" : 1
},
What wrong with it. Welcome any suggestion, explanation.
Thanks and best regards,
After researching about Map/Reduce yesterday, I realized that, "Emit" send 100 elements once, and "Reduce" perform on this data set. So my above code is wrong because it only "SUM" on small data set.
Below that is my new code for Map-Reduce
var map = function ()
{
for(var key in this.details)
{
if(key == 'Binding')
{
var value = {};
value[this.details[key]] = 1;
emit(key, value);
}
}
}
var reduce = function (key, values)
{
var reduced = {};
for(var idx = 0; idx < values.length; idx++)
{
var inner = values[idx];
for (var j in inner)
{
if (typeof (reduced[j]) == 'undefined')
{
reduced[j] = 0;
}
reduced[j] += inner[j];
}
}
return reduced;
}
I post here for anyone who meet similar situation. Thanks for reading.
Curious -- in the following example, why does the mongo REPL not store the user hash in variable 'a' past the first print?
Does it have something to do with mongo's lazy query evaluation?
> var a = db.users.find(0)
> a
{ "_id" : ObjectId("4eed6dc299cd67e275000001"), "provider" : "facebook", "uid" : "343323487", "name" : "Brian Jordan", "email" : "redacted#redacted.com" }
> a
>
You can use findOne.
> var a = db.testcoll.findOne()
> a
{
"_id" : ObjectId("4e7930a3ff647405d6000003"),
"bf" : false,
"df" : ISODate("2011-09-21T00:32:35.629Z")
}
Or you can look at its source and do something similar
> db.testcoll.findOne
function (query, fields) {
var cursor = this._mongo.find(this._fullName, this._massageObject(query) || {}, fields, -1, 0, 0, 0);
if (!cursor.hasNext()) {
return null;
}
var ret = cursor.next();
if (cursor.hasNext()) {
throw "findOne has more than 1 result!";
}
if (ret.$err) {
throw "error " + tojson(ret);
}
return ret;
}