I am using nodejs with the node-mongodb-native driver (http://mongodb.github.io/node-mongodb-native/).
I have documents with a date property stored as ISODate type.
Through nodejs, I am using this query:
db.collection("log").find({
localHitDate: {
'$gte': '2013-12-12T16:00:00.000Z',
'$lt': '2013-12-12T18:00:00.000Z'
}
})
It returns nothing. To make it work I need to do the following instead:
db.collection("log").find({
localHitDate: {
'$gte': ISODate('2013-12-12T16:00:00.000Z'),
'$lt': ISODate('2013-12-12T18:00:00.000Z')
}
})
But ISODate is not recognized in my nodejs code.
So how can I make a query against mongo date fields through my nodejs program?
Thank you
You can use new Date('2013-12-12T16:00:00.000Z') in node.js;
new is a must, because Date() is already use to return date string.
ISODate is concepted in mongodb, you can use it in mongodb console, but it can be different for different programming language.
You can use this, for me worked perfectly
//lets require/import the mongodb native drivers.
var mongodb = require('mongodb');
//We need to work with "MongoClient" interface in order to connect to a mongodb server.
var MongoClient = mongodb.MongoClient;
// Connection URL. This is where your mongodb server is running.
var url = 'mongodb://localhost/klevin';
// Use connect method to connect to the Server
MongoClient.connect(url, function (err, db) {
if (err) {
console.log('Unable to connect to the mongoDB server. Error:', err);
} else {
//HURRAY!! We are connected. :)
console.log('Connection established to', url);
// Get the documents collection
var collection = db.collection('frames');
//We have a cursor now with our find criteria
var cursor = collection.find({
tv: 'tematv',
date_created: {"$gte": new Date("2015-10-01T00:00:00.000Z") , "$lt": new Date("2017-03-13T16:17:36.470Z") }});
//We need to sort by age descending
cursor.sort({_id: -1});
//Limit to max 10 records
cursor.limit(50);
//Skip specified records. 0 for skipping 0 records.
cursor.skip(0);
//Lets iterate on the result
cursor.each(function (err, doc) {
if (err) {
console.log(err);
} else {
console.log('Fetched:', doc);
if(doc !== null){
}
}
});
}
});
we need to use new Date() is best option to get the data.
db.getCollection('orders').aggregate([
{
'$match': {
$and: [
{
status: 'UNASSIGNED'
},
{
plannedDeliveryDate: {
'$eq': new Date('2017-10-09')
}
}
]
}
},
{
$lookup: {
from: "servicelocations",
localField: "serviceLocationId",
foreignField: "serviceLocationId",
as: "locations"
}
},
{
$unwind: "$locations"
},
{
"$project": {
"accountId": 1,
"orderId": 1,
"serviceLocationId": 1,
"orderDate": 1,
"description": 1,
"serviceType": 1,
"orderSource": 1,
"takenBy": 1,
"plannedDeliveryDate": 1,
"plannedDeliveryTime": 1,
"actualDeliveryDate": 1,
"actualDeliveryTime": 1,
"deliveredBy": 1,
"size1": 1,
"size2": 1,
"size3": 1,
"jobPriority": 1,
"cancelReason": 1,
"cancelDate": 1,
"cancelBy": 1,
"reasonCode": 1,
"reasonText": 1,
"status": 1,
"lineItems": 1,
"locations": {
"lng": "$locations.location.lng",
"lat": "$locations.location.lat"
}
}
}
])
You can go through my answer, provided in other asked question.
Their instead of $eq use $gte:"yyyy-mm-dd", $lte:"yyyy-mm-dd"
NodeJS MongoDB: Querying ISO Date
Hope this will help you or somebody else!
Related
(javascript)
hello, i have a mongodb collection who have this schema:
{
_id: "any",
ids: {
user: "some value who can repeat" // and more keys but i will use this key here
},
time: 400 // can vary
}
I need to get some documents from this collection, filter to "time less than 700" and dont repeat the key "user"
I tried to use js tools for this, but in only 1 find query i get +900 documents
const ids = [];
const query = (await Personagens.find({ time: { $lt: 700 }}).sort({ time: 1 }))
.filter(x => {
if (!ids.includes(x.ids.user)) {
ids.push(x.ids.user);
return true;
}
}).slice(0, 50)
the output who shows +900 documents in 1 query
so i want to know if has some mongo db operator to filter repeated keys (the key ids.user) and get only 50 documents (obs: i use mongoose)
db.collection.aggregate([
{
"$match": {
time: {
"$gt": 700
}
}
},
{
"$group": {
"_id": "$ids.user",
"doc": {
"$push": "$$ROOT"
}
}
},
{
"$set": {
"doc": {
"$first": "$doc"
}
}
},
{
"$replaceWith": "$doc"
}
])
mongoplayground
I need to push multiple values into an array in mongoose using one call. I tried doing it using a smaller array but the array is getting inserted as a sub-array.
var kittySchema = new mongoose.Schema({
name: String,
values: [Number]
});
var Kitten = db.model('Kitten', kittySchema);
Kitten.update({name: 'fluffy'},{$push: {values:[2,3]}},{upsert:true},function(err){
if(err){
console.log(err);
}else{
console.log("Successfully added");
}
});
The result of the calling the above code thrice gives the below result:
{ "_id" : ObjectId("502b0e807809d79e84403606"), "name" : "fluffy", "values" : [ [ 2, 3 ], [ 2, 3 ], [ 2, 3 ] ] }
Whereas what I want is something like this:
{ "_id" : ObjectId("502b0e807809d79e84403606"), "name" : "fluffy", "values" : [ 2, 3 ,2 ,3, 2, 3] }
Another thing I noticed was that the type in the array (values) is specified as Number, then wouldnt the 'strict' option ensure that anything other than Numbers are not inserted ? In this case another array is being allowed to be inserted.
(Dec-2014 update) Since MongoDB2.4 you should use:
Kitten.update({name: 'fluffy'}, {$push: {values: {$each: [2,3]}}}, {upsert:true}, function(err){
if(err){
console.log(err);
}else{
console.log("Successfully added");
}
});
Deprecated see other solution below using $push $each
Your example is close, but you want $pushAll rather than $push to have each value added separately (rather than pushing another array onto the values array):
var Kitten = db.model('Kitten', kittySchema);
Kitten.update({name: 'fluffy'},{$pushAll: {values:[2,3]}},{upsert:true},function(err){
if(err){
console.log(err);
}else{
console.log("Successfully added");
}
});
Or use the $each modifier with $addToSet:
https://docs.mongodb.com/manual/reference/operator/update/addToSet/#each-modifier
// Existing tags array
{ _id: 2, item: "cable", tags: [ "electronics", "supplies" ] }
// Add "camera" and "accessories" to it
db.inventory.update(
{ _id: 2 },
{ $addToSet: { tags: { $each: [ "camera", "accessories" ] } } }
)
Currently, the updated doc doesn't support $pushAll. It seems to have been deprecated.
Now the good choice is to use the combination of $push & $each
an example:
//User schema: {uid: String, transaction: [objects] }
const filter = {"uid": uid};
const update = {
$push: {
transactions: {$each: dataarr}
}
}
User.updateOne(filter, update, {upsert:true}, (err) => {
if(err){
console.log(err)
}
})
pass {upsert: true} at options to insert if the filter returns false.
I am having a problem with understanding how the $aggregation method works in Mongoose. To be honest, I couldn't found any code examples in mongoose docs (I haven't found even [search] option on their site [google site:mongoosejs.com helps me])
So, I hope someone will help me to explain this and answer my question.
For example, I have various documents in my collection, with fields:
{ "_id": 1, "item":47139, "total_price": 560000, "quantity": 56, "lastModified" : 1491748073000 }
{ "_id": 3, "item":47140, "total_price": 1750000, "quantity": 150, "lastModified" : 1491748073000 }
and I would like to $sum all the "quantity" for documents with id: 47139 and timestamp: 1491748073000. As for now this code works fine and provides me the necessary data:
var server = mongoose.model('Name_of_my_Schema', Schema);
server.find({ lastModified : 1491748073000, item : 47139 }, null, {sort: 'buyout'},function (err, res) {
total = 0;
for (i = 0; i < res.length; i++) { //sorry, map.reduce, but not this time
total += res[i].quantity;
}
console.log(total); //in this case total = 256
});
but is it possible to do this operation via mongoose? According to mongo docs I should use this code for matching the necessary array of docs, like these:
server.aggregate().match({
lastModified : 1491748073000,
item : 47139
}).exec(function (err, result){
console.log(result);
console.log(err);
});
and then use the $group to group the necessary data and { $sum: "quantity" }, but what I should do next? Why should I use a $group, if I just want to receive a sum of all quantity?
Could someone give me a clue what am I missing?
As you have rightly said, you are missing the $group pipeline step to do the sum aggregate. Complete the pipeline as:
server.aggregate()
.match({
"lastModified": 1491748073000,
"item": 47139
})
.group({
"_id": null,
"total": { "$sum": "$quantity" }
})
.exec(function (err, result){
console.log(result);
console.log(err);
});
or as an array of operators:
server.aggregate([
{ "$match": { "lastModified": 1491748073000, "item": 47139 } },
{ "$group": { "_id": null, "total": { "$sum": "$quantity" } } }
]).exec(function (err, result){
console.log(result);
console.log(err);
});
I am having hard time figuring out how to increment a value in an object within an array
For instance I have this document based on Poll schema:
{
"_id": "584b2cc6817758118e9557d8",
"title": "Number of Skittles",
"description": "Test1",
"date": "Dec 9, 2016",
"__v": 0,
"labelOptions": [
{
"Bob": 112
},
{
"Billy": 32
},
{
"Joe": 45
}
]
}
Using express, I am able to get this far:
app.put('/polls/:id', function(req, res){
let id = req.params.id;
let labelOption = req.query.labelOption;
Poll.findOneAndUpdate(
{'_id' : id},
{$inc: {`labelOptions.$.${labelOption}`: 1 }},
function(err){
console.log(err)
})
where labelOption is the one that I would like to increment its value
To be more concise, I am having trouble transversing inside the document.
It is not possible to directly increment the value in the .find query if labelOptions is an Array of Object. To make it easier, you should change the labelOptions type from Array of Objects to Object:
"labelOptions": {
"Bob": 112,
"Billy": 32,
"Joe": 45
};
Also consider using .findByIdAndUpdate instead of .findOneAndUpdate if you are querying by the document's _id. And then, you can achieve what you want by:
Poll.findByIdAndUpdate(
id,
{$inc: {`labelOptions.${labelOption}`: 1 }},
function(err, document) {
console.log(err);
});
UPDATE: If you are persistent on using Array of Objects for labelOptions, there is a workaround:
Poll.findById(
id,
function (err, _poll) {
/** Temporarily store labelOptions in a new variable because we cannot directly modify the document */
let _updatedLabelOptions = _poll.labelOptions;
/** We need to iterate over the labelOptions array to check where Bob is */
_updatedLabelOptions.forEach(function (_label) {
/** Iterate over key,value of the current object */
for (let _name in _label) {
/** Make sure that the object really has a property _name */
if (_label.hasOwnProperty(_name)) {
/** If name matches the person we want to increment, update it's value */
if (_name === labelOption) ++_label._name;
}
}
});
/** Update the documents labelOptions property with the temporary one we've created */
_poll.update({labelOptions: _updatedLabelOptions}, function (err) {
console.log(err);
});
});
There is another way to do this which allows a more flexible document model. If you add a field to your object like:
{
"_id": "584b2cc6817758118e9557d8",
"title": "Number of Skittles",
"description": "Test1",
"date": "Dec 9, 2016",
"__v": 0,
"labelOptions": [
{
"name": "Bob",
"number": 112
},
{
"name": "Billy",
"number": 32
},
{
"name": "Joe"
"number": 45
}
]
}
Then you can do:
app.put('/polls/:id', function(req, res){
let id = req.params.id;
let labelOption = req.query.labelOption;
Poll.findOneAndUpdate(
{
'_id' : id,
'labelOptions.name
},
{$inc: {
`labelOptions.$.number`: 1
}},
function(err){
console.log(err)
})
I am querying a list of items and only returning the items with contain a given ID in the provider_cost_dict. For instance, if I pass providerId = 10001, then only items with an entry in provider_cost_dict that match the provider ID will return.
How can I modify my code so that I can omit all the provider_cost_dict's that do not match the provider ID?
Here is my current code:
var procedures = db.collection('procedures');
var query = {};
query['provider_cost_dict.' + req.query.providerId] = {$exists: true };
procedures.find({}).toArray(function(err, result) {
// Send the result back via JSON.
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify(result, null, 3));
});
Here is what my response looks like:
{
"_id": "57c62cb53673aaf5f6beacf9",
"natl_total_cost": 1274787840,
"natl_average": 8338.487,
"natl_report_count": 152880,
"name": "COPD (WITH MAJOR COMPLICATIONS)",
"provider_cost_dict": {
"10001": {
"report_count": 144,
"total_cost": 957334,
"average_cost": 6648.153
},
"10005": {
"report_count": 200,
"total_cost": 1321644,
"average_cost": 6608.22
},
"10006": {
"report_count": 214,
"total_cost": 1345658,
"average_cost": 6288.1216
If I passed `10001 how could I make my return look like:
{
"_id": "57c62cb53673aaf5f6beacf9",
"natl_total_cost": 1274787840,
"natl_average": 8338.487,
"natl_report_count": 152880,
"name": "COPD (WITH MAJOR COMPLICATIONS)",
"provider_cost_dict": {
"10001": {
"report_count": 144,
"total_cost": 957334,
"average_cost": 6648.153
}
}
You can specify a projection to the query so that only your desired cost dict is shown like so
var query = { 'provider_cost_dict.10001': { $exists: true } };
var project = {
'natl_total_cost': 1,
'natl_average': 1,
'natl_report_count': 1,
'name': 1,
'provider_cost_dict.10001': 1
};
procedures.find(query, project).toArray( ...