MongoDB Range Issue - javascript

I'm using nodejs and mongodb.
I want to search docs between a num range but the function always give me number that outside the range. For example, this is my function and I want to get the results of the docs that they has a field size with the numbers between 1 to 1200:
db.collection(example).find({
size: {
"$gte": 1,
"$lte": 1200
}
}).toArray(function(err, results) {
db.close();
console.log("results=" + results);
});
the doc in the Database:
{ "_id" : ObjectId("56659a492b9eaad2d9e6d4d2"), "size" : -1 }
{ "_id" : ObjectId("56659a492b9eaad2d9e6d4d3"), "size" : 100 }
{ "_id" : ObjectId("56659a492b9eaad2d9e6d4d4"), "size" : 800 }
{ "_id" : ObjectId("56659a492b9eaad2d9e6d4d5"), "size" : 1999 }
the result of the query should be:
{ "_id" : ObjectId("56659a492b9eaad2d9e6d4d3"), "size" : 100 }
{ "_id" : ObjectId("56659a492b9eaad2d9e6d4d4"), "size" : 800 }
but the query result is:
{ "_id" : ObjectId("56659a492b9eaad2d9e6d4d2"), "size" : -1 }
{ "_id" : ObjectId("56659a492b9eaad2d9e6d4d3"), "size" : 100 }
{ "_id" : ObjectId("56659a492b9eaad2d9e6d4d4"), "size" : 800 }
{ "_id" : ObjectId("56659a492b9eaad2d9e6d4d5"), "size" : 1999 }

I believe you need to use a $and clause on your size conditions. It might look something like this:
db.collection(example).find( {
$and: [
{ size: { $gte: 1 } },
{ size: { $lte: 1200 } }
] } ).toarray...
See the examples in the mongo docs here.
Edit: Actually, an implicit and was fine. As noted, the actual problem here was size values were stored as strings, not ints.

Related

Re-structure the data of the MongoDB $lookup Query.

I want this to be the result
help me, thank you
{
"_id" : ObjectId("5b74f57d3eb9591fcc069406"),
"received_by" : ObjectId("5b6bac617e9f754ff8aebd65"),
"received_date" : "2019",
"code" : "TRSV16081800007",
"items" : [
{
"m_souvenir_id" : ObjectId("5b70e98ccb72df3bec00c94a"),
"qty" : "10"
},
{
"m_souvenir_id" : ObjectId("5b70e98ccb72df3bec00c94a"),
"qty" : "10"
},
]
}
the result is like this
{
"_id" : ObjectId("5b74f57d3eb9591fcc069406"),
"received_by" : ObjectId("5b6bac617e9f754ff8aebd65"),
"received_date" : "2019",
"code" : "TRSV16081800007",
"items" : [
{
"m_souvenir_id" : ObjectId("5b70e98ccb72df3bec00c94a"),
"qty" : "10"
}
]
}
/* 2 */
{
"_id" : ObjectId("5b74f57d3eb9591fcc069406"),
"received_by" : ObjectId("5b6bac617e9f754ff8aebd65"),
"received_date" : "2019",
"code" : "TRSV16081800007",
"items" : [
{
"m_souvenir_id" : ObjectId("5b70e9d7cb72df3bec00c94b"),
"qty" : "20"
}
]
}
I have a project with nosql in mongodb
I have a problem with nosql in mongodb, I've tried searching in various sources, but the results are still not what I wantI have a project like this in mongodb,
db.t_souvenir.aggregate([
{ $lookup: { from: "t_souvenir_item", localField:"_id", foreignField:"t_souvenir_id", as: "Items"}},
{ $unwind : "$Items" },
{ $project : {
"code":1,
"received_by":1,
"received_date":1,
items : {
"m_souvenir_id":"$Items.m_souvenir_id",
"qty":"$Items.qty",
},
}};**strong text**
]);

Merge arrays and group to produce a count for each combined array value

I have a dataset like this:
{
"_id" : ObjectId("5a4c6fb6993a721b3479a27e"),
"score" : 8.3,
"page" : "message",
"lastmodified" : ISODate("2018-01-03T06:49:19.232Z"),
"createdate" : ISODate("2018-01-03T05:52:54.446Z"),
"slug" : [
"#APPLE"
],
"__v" : 0
},
{
"_id" : ObjectId("5a4c6fb6993a721b3479a27e"),
"score" : 9.3,
"page" : "#BANANA",
"lastmodified" : ISODate("2018-01-03T06:49:19.232Z"),
"createdate" : ISODate("2018-01-03T05:52:54.446Z"),
"slug" : [
"#APPLE"
],
"__v" : 0
}
{
"_id" : ObjectId("5a4c6fb6993a721b3479a27e"),
"score" : 5.3,
"page" : "#BANANA",
"lastmodified" : ISODate("2018-01-03T06:49:19.232Z"),
"createdate" : ISODate("2018-01-03T05:52:54.446Z"),
"slug" : [
"#BANANA"
],
"__v" : 0
}
Now I want to calculate the sum of score according to my Filter Like this:
#APPLE: 8.3+9.3 = 17.6 i.e #APPLE: 17.6,
#BANANA: 9.3+5.3 = 14.6 i.e #BANANA: 14.6
So for this I have to pick only last 1 hour data rather than picking the whole database
. So my query is like this
var newTime = new Date();
newTime.setHours( newTime.getHours() - 1 );
db.Test.find({"lastmodified":{$gt: newTime}})
so By this I can get only last 1 hour value. Now I am confuse that how i can do sum with filter. I also attached filter query i.e
db.Test.find({"lastmodified":{$gt: newTime}}, {$or: [{slug: {$in: ['#APPLE']}}, {page: '#APPLE'}]})
But it does not give anything. any help is appreciated
Try this aggregate query...
db.tests.aggregate([{
"$unwind": "$slug"
},
{
"$group": {
"_id": "$slug",
"totalScore": {
"$sum": "$score"
}
}
}
]);
Result:
{
"_id" : "#BANANA",
"totalScore" : 5.3
}
{
"_id" : "#APPLE",
"totalScore" : 17.6
}

Mongoose (MongoDB) - Error: Can't use $each with Number

I've to push a given array of Number values into a selected Document inside my MongoDB database.
The Document that I'm going to update as the following structure:
{
"_id" : {
"id" : 17,
"type" : "f"
},
"__v" : 0,
"created_at" : ISODate("2017-03-22T11:16:21.403Z"),
"token" : {
"expDate" : ISODate("2017-12-31T00:00:00Z"),
"token" : "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbWFpbCI6ImFsYWRpbkBjb25zb3J6aW9jZXIuaXQiLCJleHAiOjE1MTQ2Nzg0MDB9.QvbT146bA_KH5XA7MH8ASXm9cr3sPZChJ3prYyDireI"
},
"updated_at" : ISODate("2017-07-24T09:42:33.741Z"),
"plots" : {
"idPlot" : [
23570,
23475
]
},
"machines" : [
{
"idPlotBind" : 1,
"ip" : "",
"mac" : "18-5F-00-4A-FE-F4",
"irrId" : 31,
"_id" : ObjectId("59084f527d634d301338aac6"),
"addr" : "pialadin.ddns.net"
},
{
"idPlotBind" : null,
"ip" : "",
"mac" : "12-01-02-FE-AB-B2",
"irrId" : 35,
"_id" : ObjectId("59084f7d7d634d301338aac7")
}
]
}
I'm using the Mongoose library for JS, and the accused query is this one:
userSchema.findOneAndUpdate({$and:[{ '_id.id': resData.PlotRows.IdUser}, {'_id.type': 'f'}]},{$addToSet:{'plots.$.idPlot': {$each: plotData}}}, {upsert: false}, function(err, usr){
if(err){
console.log(err);
return;
}
});
But when I try to execute it, gives me back:
Error: Can't use $each with Number

Mongodb / JS: find the minimum (earliest) date

I'm trying to find the minimum date of all documents in a collection. I have approached this so far with a sort function and taking the first one that I find, see here:
earliestTime = function (kitUser) {
'use strict';
var res, earliestTime;
res = Cards.findOne({ kit: kitUser }, { fields: { created: 1 } }, { sort: { created: 1 } });
console.log('Created date: ' + res.created);
earliestTime = new Date(res.created - 20000);
console.log('Earliest time: ' + earliestTime);
return earliestTime;
};
I then subtract 20 seconds from the value I've found and return that value to insert a new document which has 20 seconds less in the created fields than the earliest I've found before.
modifierObject = {};
modifierObject.created = earliestTime(kitUser);
The function earliestTime delivers the right results when I look at the console output:
I20160516-15:53:14.849(7)? Created date: Wed Apr 06 2016 12:00:11 GMT+0700 (ICT)
I20160516-15:53:14.849(7)? Earliest time: Wed Apr 06 2016 11:59:51 GMT+0700 (ICT)
However, when this function is called 21 times with a couple of read/write operations in between each call, each inserted document has the same timestamp in the created field:
{ "_id" : "xcd3EfKfS6iLGvcsP", "created" : ISODate("2016-04-06T04:59:51.183Z") }
{ "_id" : "bvL3f8NHHZM8Ytdma", "created" : ISODate("2016-04-06T04:59:51.183Z") }
{ "_id" : "gAirEbicdWJz9CELB", "created" : ISODate("2016-04-06T04:59:51.183Z") }
{ "_id" : "kgAg6Jt2P89mTJYgN", "created" : ISODate("2016-04-06T04:59:51.183Z") }
{ "_id" : "xeqR5K2fxNmgEv4bb", "created" : ISODate("2016-04-06T04:59:51.183Z") }
{ "_id" : "PgPimNRxj2zBuS8M2", "created" : ISODate("2016-04-06T04:59:51.183Z") }
{ "_id" : "snwEWeXpn4Ampsito", "created" : ISODate("2016-04-06T04:59:51.183Z") }
{ "_id" : "8RCS8YQLxY7tY6Ruk", "created" : ISODate("2016-04-06T04:59:51.183Z") }
{ "_id" : "tEqRJs49RNvCzkMz6", "created" : ISODate("2016-04-06T04:59:51.183Z") }
{ "_id" : "PJnZ7Z4WH6rTTw626", "created" : ISODate("2016-04-06T04:59:51.183Z") }
{ "_id" : "J2L6KPhzxcva3rttJ", "created" : ISODate("2016-04-06T04:59:51.183Z") }
{ "_id" : "YR5R6ShakPxCXgj54", "created" : ISODate("2016-04-06T04:59:51.183Z") }
{ "_id" : "Ajd6D8E8WrRB47q7d", "created" : ISODate("2016-04-06T04:59:51.183Z") }
{ "_id" : "g5CQgjbPH7NoytyMw", "created" : ISODate("2016-04-06T04:59:51.183Z") }
{ "_id" : "s9NgtsiR7WbjgeKLr", "created" : ISODate("2016-04-06T04:59:51.183Z") }
{ "_id" : "NPtZMHkAdqySShD3a", "created" : ISODate("2016-04-06T04:59:51.183Z") }
{ "_id" : "XxpWREjutAjbgHyME", "created" : ISODate("2016-04-06T04:59:51.183Z") }
{ "_id" : "6ZsiL2ZgidWjk3cgb", "created" : ISODate("2016-04-06T04:59:51.183Z") }
{ "_id" : "pvXiEaJgkuHEKijbB", "created" : ISODate("2016-04-06T04:59:51.183Z") }
{ "_id" : "im4GzumrE6RARNLbe", "created" : ISODate("2016-04-06T04:59:51.183Z") }
I'm puzzle as to how this can happen. The result which I was expecting would be (timestamps):
"created" : ISODate("2016-04-06T04:59:51.183Z")
"created" : ISODate("2016-04-06T04:59:41.183Z")
"created" : ISODate("2016-04-06T04:59:31.183Z")
"created" : ISODate("2016-04-06T04:59:21.183Z")
I suspect it's something wrong with my function with the sort, hence my question how I can easier find the minimum of a date in MongoDB.
Thanks in advance!
Ok, I've found an error in my projection, the 4th line has to be:
res = Cards.findOne({ kit: kitUser }, { fields: { created: 1 }, sort: { created: 1 } });
I've overlooked that the projection is one object and therefore the first bracket has to be around all the options like fields and sort.
This article has been very helpful in identifying it and thanks to Marcel Fahle for pointing to it:
https://themeteorchef.com/snippets/mongodb-queries-and-projections/

taking the difference between adjacent documents in mongoDB

How do I take the difference between adjacent records in mongoDB using javascript? For example, if I have the following three documents in a collection:
{
"_id" : ObjectId("50ed90a55502684f440001ac"),
"time" : ISODate("2013-02-13T15:45:41.148Z")
}
{
"_id" : ObjectId("50ed90a55502684f440001ad"),
"time" : ISODate("2013-02-13T15:45:42.148Z")
}
{
"_id" : ObjectId("50ed90a55502684f440001ae"),
"time" : ISODate("2013-02-13T15:45:45.148Z")
}
I want to take the difference in the "time" field between adjacent values to get:
{
"_id" : ObjectId("50ed90a55502684f440001ac"),
"time" : ISODate("2013-02-13T15:45:41.148Z"),
"time_difference" : null
}
{
"_id" : ObjectId("50ed90a55502684f440001ad"),
"time" : ISODate("2013-02-13T15:45:42.148Z"),
"time_difference" : 1
}
{
"_id" : ObjectId("50ed90a55502684f440001ae"),
"time" : ISODate("2013-02-13T15:45:45.148Z"),
"time_difference" : 3
}
Any ideas on how to do this efficiently in javascript/mongoDB? Thanks.
I don't know whether this was true when the question was asked seven years ago, but this can be solved completely within the aggregation framework. Assuming the collection name is AdjacentDocument, the following aggregation will get the results you're looking for:
db.AdjacentDocument.aggregate(
{$sort: {time: 1}},
{$group: {_id: 0, document: {$push: '$$ROOT'}}},
{$project: {documentAndPrevTime: {$zip: {inputs: ['$document', {$concatArrays: [[null], '$document.time']}]}}}},
{$unwind: {path: '$documentAndPrevTime'}},
{$replaceWith: {$mergeObjects: [{$arrayElemAt: ['$documentAndPrevTime', 0]}, {prevTime: {$arrayElemAt: ['$documentAndPrevTime', 1]}}]}},
{$set: {time_difference: {$trunc: [{$divide: [{$subtract: ['$time', '$prevTime']}, 1000]}]}}},
{$unset: 'prevTime'}
);
Aggregation pipeline walkthrough
First, the documents are sorted from oldest to newest. They are grouped into a single document with the documents stored in an ordered array field:
{$sort: {time: 1}},
{$group: {_id: 0, document: {$push: '$$ROOT'}}}
/*
{
"_id" : 0,
"document" : [
{
"_id" : ObjectId("50ed90a55502684f440001ac"),
"time" : ISODate("2013-02-13T15:45:41.148Z")
},
{
"_id" : ObjectId("50ed90a55502684f440001ad"),
"time" : ISODate("2013-02-13T15:45:42.148Z")
},
{
"_id" : ObjectId("50ed90a55502684f440001ae"),
"time" : ISODate("2013-02-13T15:45:45.148Z")
}
]
}
*/
Next, the previous times are zipped into the document array, creating an array of [document, previousTime]:
{$project: {documentAndPrevTime: {$zip: {inputs: ['$document', {$concatArrays: [[null], '$document.time']}]}}}}
/*
{
"_id" : 0,
"documentAndPrevTime" : [
[
{
"_id" : ObjectId("50ed90a55502684f440001ac"),
"time" : ISODate("2013-02-13T15:45:41.148Z")
},
null
],
[
{
"_id" : ObjectId("50ed90a55502684f440001ad"),
"time" : ISODate("2013-02-13T15:45:42.148Z")
},
ISODate("2013-02-13T15:45:41.148Z")
],
[
{
"_id" : ObjectId("50ed90a55502684f440001ae"),
"time" : ISODate("2013-02-13T15:45:45.148Z")
},
ISODate("2013-02-13T15:45:42.148Z")
]
]
}
*/
Next, the document & time array is unwound, creating a document for each of the initial documents:
{$unwind: {path: '$documentAndPrevTime'}}
/*
{
"_id" : 0,
"documentAndPrevTime" : [
{
"_id" : ObjectId("50ed90a55502684f440001ac"),
"time" : ISODate("2013-02-13T15:45:41.148Z")
},
null
]
}
{
"_id" : 0,
"documentAndPrevTime" : [
{
"_id" : ObjectId("50ed90a55502684f440001ad"),
"time" : ISODate("2013-02-13T15:45:42.148Z")
},
ISODate("2013-02-13T15:45:41.148Z")
]
}
{
"_id" : 0,
"documentAndPrevTime" : [
{
"_id" : ObjectId("50ed90a55502684f440001ae"),
"time" : ISODate("2013-02-13T15:45:45.148Z")
},
ISODate("2013-02-13T15:45:42.148Z")
]
}
*/
Next, we replace the document with the value of the document array element, merged with previous time element (using null if it's the initial index):
{$replaceWith: {$mergeObjects: [{$arrayElemAt: ['$documentAndPrevTime', 0]}, {prevTime: {$arrayElemAt: ['$documentAndPrevTime', 1]}}]}}
/*
{
"_id" : ObjectId("50ed90a55502684f440001ac"),
"time" : ISODate("2013-02-13T15:45:41.148Z"),
"prevTime" : null
}
{
"_id" : ObjectId("50ed90a55502684f440001ad"),
"time" : ISODate("2013-02-13T15:45:42.148Z"),
"prevTime" : ISODate("2013-02-13T15:45:41.148Z")
}
{
"_id" : ObjectId("50ed90a55502684f440001ae"),
"time" : ISODate("2013-02-13T15:45:45.148Z"),
"prevTime" : ISODate("2013-02-13T15:45:42.148Z")
}
*/
Finally, we update the document by setting the time_difference to the difference of the two time fields, and removing the temporary prevTime field. Since the difference between two dates is in milliseconds and your example uses seconds, we calculate the seconds by dividing by 1000 and truncating.
{$set: {time_difference: {$trunc: [{$divide: [{$subtract: ['$time', '$prevTime']}, 1000]}]}}},
{$unset: 'prevTime'}
/*
{
"_id" : ObjectId("50ed90a55502684f440001ac"),
"time" : ISODate("2013-02-13T15:45:41.148Z"),
"time_difference" : null
}
{
"_id" : ObjectId("50ed90a55502684f440001ad"),
"time" : ISODate("2013-02-13T15:45:42.148Z"),
"time_difference" : 1
}
{
"_id" : ObjectId("50ed90a55502684f440001ae"),
"time" : ISODate("2013-02-13T15:45:45.148Z"),
"time_difference" : 3
}
*/
The one thing you will want to make sure of here is that you have a sort on the query you wish to use to garnish your records. If no sort is used it will actually use find order, which is not $natural order.
Find order can differ between queries so if you run the query twice within the period of 2 minutes you might find that they don't return the same order. It does seem however that your query would be logically sorted on tiem_difference.
It should also by noted that this is not possible through normal querying. I also do not see an easy way doing this through the aggregation framework.
So already it seems the next plausible method is either using multiple queries or client side processing. Client side processing is probably the better here using a function like the one defined by #Marlon above.
One thing, I want to clear you. Unlike MYSQL, MongoDB is not give gurantee to the position. I mean, MongoDB will give you different sort at different time. So compare adjacent document may give different result, on every reading.
If you are fine with that and you want to compare then try with MongoDB's MapReduce http://docs.mongodb.org/manual/applications/map-reduce/
Assuming those 3 objects are coming through in an array, you could do something like the below:
var prevTime;
var currentTime;
for(var i = 0; i < records.length; i++)
{
currentTime = new Date(records[i].time).getTime();
records[i].time_difference = currentTime - prevTime;
prevTime = currentTime;
}
Of course you'll need to swap bits out to make it use the records from mongo.
If you need to do any more complex date calculations, I highly suggest checking out datejs (which you can get a node wrapper for if you want).

Categories