Retrieving data from MongoDB database with certain data range - node.js

In nodeJS I am retrieving data from a mongoDB database. It works for all other cases ({"name": 'user1'} as find critera), expect when specifying a date range for which I would like to receive data for.
var collection = db.collection('collectionName');
collection.find(
{ "date": { $gte: new Date("2010-12-01"), $lt: new Date("2010-12-10")} }
,
{}, (function (err, result) {
if (err) {
console.log(err);
} else if (result.length) {
console.log(result);
}
}));
It must be noted that date data includes a timestamp date which was inserted using new Date() function
Document Stored in Collections:
[ { _id: 5849d924da9a361b503e8945,
name: 'user2',
date: 'Mon Dec 08 2010 22:05:23 GMT+0000 (GMT Standard Time)'
},
{ _id: 5849dabb2a9fdc2310d37c0e,
name: 'user1',
date: 'Thu Dec 01 2010 20:12:11 GMT+0000 (GMT Standard Time)'
} ]

Related

Mongoose gte date object wont find record

I have a Mongo-DB with one record, the following:
{
"_id": "608c0f5ceee3254fcb0f9d1f",
"outDated": false,
"domain": "test.com",
"releaseDate": "Tue May 04 2021 02:00:00 GMT+0200 (Central European Summer Time)",
"__v": 0
}
My Node.js-code looks like this:
getDomainsFromTodaysDate: async () => {
await module.exports.connectToDb();
return Domains.find({
releaseDate: { $gte: new Date(dayjs().format('YYYY-MM-DD')) }
})
.then(res => {
return res;
})
.catch(error => {
console.log(`getDomainsFromTodaysDate error: ${error}`);
});
}
The dayjs-function output is:
const test = new Date(dayjs().format('YYYY-MM-DD'));
console.log(test) // 2021-04-30T14:30:11.000Z
console.log(typeof test) // object
Mongoose-debug gives me this:
Mongoose: domains.find({ releaseDate: { '$gte': 'Fri Apr 30 2021 16:06:06 GMT+0200 (Central European Summer Time)' }}, { projection: {} })
Still I dont get the record stated above from the DB. What am I doing wrong? Without the releaseDate-filter I receive the record.
Edit:
Here is part of the Schema where releaseDate appears:
return new mongoose.Schema({
createdAt: String,
outDated: Boolean,
domain: String,
releaseDate: Date
});
From Robo3t:

issue with update in mongoose 3.10.8

I am trying to update a collection using Mongoose 3.10.8
let findQuery = {username: data.username};
let updateQuery ={
"$addToSet":{
"schemes":{
"$each":[data.schemes]
}
}
};
return new Promise((resolve, reject) => {
this.modelInstance.update(findQuery, updateQuery).exec((err, result) => {
if(err) {
console.log(err);
} else {
resolve(result);
}
})
})
But my code triggers the following error:
{ MongoError: '$set' is empty. You must specify a field like so: {$set: {: ...}}
If I enable debug mode with mongoose.set('debug',true), I see that there is an empty $set in the query.
Mongoose: studentnotifications.update(
{ username: 'username1' },
{
'$set': {},
'$setOnInsert': {
created_at: new Date("Fri, 15 Sep 2017 12:51:36 GMT")
}, '$addToSet': {
schemes: {
'$each': [ { schemeName: 'scheme1' } ]
}
}
},
{ overwrite: undefined }
)
Then am I supposed to disable set?
OK, after reading the following document
https://github.com/Automattic/mongoose/wiki/3.8-Release-Notes#modelupdate-now-supports-overwrite
I had to set an option {overwrite:true}
But how do I disable to the updatedAt: new Date("Fri, 15 Sep 2017 13:02:28 GMT"), created_at: new Date("Fri, 15 Sep 2017 13:02:28 GMT")
Because I am getting the error
{ MongoError: The dollar ($) prefixed field '$addToSet' in '$addToSet' is not valid for storage.
If I remove the updatedAt field the data is getting updated while running it in the command prompt

how can I construct my mongoose query so that at least one of two statements is always taken under consideration?

In my application user can add entry that is visible
This is my mongoose query:
Mongoose: test.find({updated_at: { '$gte': new Date("Fri, 14 Oct 2011
00:00:00 GMT"), '$lte': new Date("Fri, 14 Oct 2016 20:12:14 GMT") },
username: { '$in': [ 'XXXXXXXXX', 'YYYYYYYYYYYYYY' ] }, '$or': [ {
myFlag: false } ] }) { fields: undefined }
and this is how I construct it:
if (friends != undefined) {
var friendsSplitted = friends.split(",");
query = query.where("username").in(friendsSplitted);
}
if (publicEntries != undefined && publicEntries === "true") {
query = query.or({myFlag: false});
}
This query basically says:
look for all content that belongs to your friends OR for any content
that has myFlag set up to false.
I want to change it so that is says:
look for all content that belongs to your friends AND ALSO for any content that has myFlag set up to false (BUT NOT necessarily belongs to your friends).
Can you help me with that?
You should try both queries inside $or as below:
test.find({'$or': [ { myFlag: false },
{updated_at: { '$gte': new Date("Fri, 14 Oct 2011 00:00:00 GMT"),
'$lte': new Date("Fri, 14 Oct 2016 20:12:14 GMT") },
username: { '$in': [ 'XXXXXXXXX', 'YYYYYYYYYYYYYY' ] } ] })
Hope this helps!
comment me if i missed something.

MongoDB: select all fields + all matched elements of subcollection

Here is one document from my mongoose collection:
{ _id: 55ae7be99e772a7c025a0a7b,
id: 'foo',
isBoolean: true,
kind: 'bar',
values:
[
{ y: 0,
x: Wed Aug 26 2015 11:12:56 GMT+0200 (Mitteleuropäische Sommerzeit),
_id: 55ae7ae05596dd740eb8a204 },
{ y: 0,
x: Wed Aug 26 2015 11:12:57 GMT+0200 (Mitteleuropäische Sommerzeit),
_id: 55ae7ae05596dd740eb8a203 },
{ y: 1,
x: Wed Aug 26 2015 11:12:56 GMT+0200 (Mitteleuropäische Sommerzeit);
_id: 55ae7be91fa1511c1795c5ae }
]
}
So, I need to find all documents, that have specific value.x. After that I need to return that document with all fields and found value elements.
Wenn I try it with
.find({'values.x': mTime1})
.select({
'_id' : 1 ,
'id' : 1 ,
'kind' : 1 ,
'isBoolean' : 1 ,
'values' : {$elemMatch: {x: time1}}
})
I receive just the firsTt found value:
{ ...
values:
[ { exceeds: null,
y: 0,
x: Wed Aug 26 2015 11:12:56 GMT+0200 (Mitteleuropäische Sommerzeit),
_id: 55ae7d86870b92b8056bed4c } ]
}
Next version
.aggregate({"$unwind" : "$values"}, {"$match" : {"values.x": time1}},
{"$group" : {
'_id' : '$_id',
'values' : {$addToSet: "$values"}
});
returns all matched values except other fields...
My goal is:
{ _id: 55ae7be99e772a7c025a0a7b,
id: 'foo',
isBoolean: true,
kind: 'bar',
values:
[
{ y: 0,
x: Wed Aug 26 2015 11:12:56 GMT+0200 (Mitteleuropäische Sommerzeit),
_id: 55ae7ae05596dd740eb8a204 },
{ y: 1,
x: Wed Aug 26 2015 11:12:56 GMT+0200 (Mitteleuropäische Sommerzeit);
_id: 55ae7be91fa1511c1795c5ae }
]
}
Have you any idea, how to achieve that with mongoose?? :)
Update:
Thanks to tsturzl, I solved it with next function (without changing the model):
self.aggregate(
{'$unwind' : '$values'},
{'$match' : { 'values.x': mTime1} },
{'$group' : {
'_id' : '$_id',
'values' : {$push: '$values'}
}}
)
.exec(
function(err, results) {
if(err) return done(err);
var values = {}; // hashMap to group values
results.forEach(function(item) {
if(item.values) // prevent empty results
values[item._id] = item.values;
});
self.find({_id:{$in: _.keys(values)}})
.exec(function(err, items) {
if(err) return done(err);
var results = items.map(function(item) {
item.values = values[item._id];
return item;
});
done(err, results); // callback results
});
});
The problem with using elemMatch in a projection is that it accesses a single item. Similar to an array arr[1], elemMatch fetches the index of the item in the array and then projects that array item at that index. So you can only retrieve one sub-document using this method.
You can use an aggregation similar to this
[
{$match: {'values.x': mTime1}}, //match before to reduce size of unwound
{$unwind: '$values'},
{$match: {'values.x': mTime1}},
{$group: {
_id: '$_id',
id: {$first: '$id'},
kind: {$first: '$kind'},
isBoolean: {$first: '$isBoolean'},
values: {$push: '$values'}
}
]
I've tested this to work fine locally on an array of subdocuments.
It's possible that your approach is best suited to being restructured. You should remodel your data so that your values have their own collection and reference by _id. In this cause I would store the reference in the values collection.
Remove values field from this collection
{ _id: 55ae7be99e772a7c025a0a7b,
id: 'foo',
isBoolean: true,
kind: 'bar'
}
Values Model:
{
y: Number,
x: Date,
parentId: {type: ObjectId, ref: "myColl"} //make sure you require ObjectId and rename the reference
}
You can then do something like this
ValuesModel.find({
x: mTime1
}).exec(function(err, results) {
var ids = {}; //hashMap to group values
var idsArr = []; //array of ids
results.forEach(function(item) {
if(!ids.hasOwnProperty(items.parentId.toString())) {
ids[items.parentId.toString()] = [];
idArr.push(item.parentId);
}
ids[items._id.toString()].push(item);
});
myColl.find({_id:{$in: idsArr}})
.exec(function(err, items) {
var results = items.map(function(item) {
item.values = ids[item._id.toString()];
return item;
});
done(results); //callback results
});
});
This will grab all values that you queried for, then group them in a hashMap and push all the parentIds to an array. Then I query for that array of parentIds. I take the hashMap, reference it by the id in the hashMap and create a new field for .values in the parent document. This will prevent you from having to use aggregations, which aren't as scalable, and will allow you to easily query the values table. If you want to find only one value you can simply use the mongoose populate method. The downfall to this approach is that you need to do more work in your code, and you have 2 round trips. However, this should still be more efficient than an aggregation.
This can be used to create a reusable method to simplify your code if you query into values a lot
function queryValues(query, done) {
ValuesModel.find(query).exec(function(err, results) {
if(err) return done(err);
var ids = {}; //hashMap to group values
var idsArr = []; //array of ids
results.forEach(function(item) {
if(!ids.hasOwnProperty(items.parentId.toString())) {
ids[items.parentId.toString()] = [];
idArr.push(item.parentId);
}
ids[items._id.toString()].push(item);
});
myColl.find({_id:{$in: idsArr}})
.exec(function(err, items) {
if(err) return done(err);
var results = items.map(function(item) {
item.values = ids[item._id.toString()];
return item;
});
done(null, results); //callback results
});
});
}
Then you can just call queryValues({x: mTime1}, function(err, results){...});, and you can pass any query you want and the function will handle populating the parent document without fetching duplicate data for maximum efficiency.
One thing I might also recommend is that you define this method as a schema static method in your model definition so you can tuck this code away and never have to worry. See: http://mongoosejs.com/docs/api.html#schema_Schema-static

Issue ordering by date with mongoose

This is my Schema:
var userschema = new mongoose.Schema({
user: String,
imagen: [{
name: String,
author: String,
date: { type: Date, default: Date.now },
}],
follow: [String]
});
And this is the code:
usermodel.findOne({ user: req.session.user }, function (err, user){
usermodel.find({ _id: {$in: user.follow } }, function (err, images){
console.log(images);
if (err) throw err;
res.render('home.ejs', {
user: user,
following: images
});
});
});
The follow array in the Schema contains the _ids of the users that the actual user is following. I'm trying to get an output like this:
{ _id: 50fd9c7b8e6a9d087d000006,
imagen:
[ { name: 'fff.png',
author: 'foo',
_id: 50fd9ca2bc9f163e7d000006,
date: Mon Jan 21 2013 20:53:06 GMT+0100 (CET) },
{ name: 'mmm.png',
author: 'foo',
_id: 50fda83a3214babc88000005,
date: Mon Jan 21 2013 21:41:34 GMT+0100 (CET) } ] },
{ _id: 50fd9d3ce20da1dd7d000006,
imagen:
[ { name: 'ddd.jpg',
author: 'faa',
_id: 50fda815915e068387000005,
date: Mon Jan 21 2013 21:42:57 GMT+0100 (CET) } ] }
And I'm trying to get an output similar at this, for example:
{ [ { name: 'fff.png',
author: 'foo',
_id: 50fd9ca2bc9f163e7d000006,
date: Mon Jan 21 2013 20:53:06 GMT+0100 (CET) },
{ name: 'ddd.png',
author: 'faa',
_id: 50fda815915e068387000005,
date: Mon Jan 21 2013 21:42:34 GMT+0100 (CET) },
{ name: 'mmm.png',
author: 'foo',
_id: 50fda83a3214babc88000005,
date: Mon Jan 21 2013 21:41:34 GMT+0100 (CET) }
] }
I think that what I want is imposible, or very complex, is there any solution for this...?
Thank's advance!
In this line:
usermodel.find({ _id: {$in: user.follow } }, function (err, images){
images is not good name, nicer name is users or even docs (you'll have an array of documents of usermodel schema there). So images in your code are found documents.
I've made a little test with the same schema as you gave. Here is the part where I join all user.imagen arrays and then sort them (of course it is test case but it works, hope this will lead you to the right way):
User.find {}, (err, users) ->
all_images = []
# iterate users array to join all imagen arrays
for user in users
all_images.push user.imagen
# flatten nested arrays in all_images with underscore function
all_images = _.flatten all_images
# sort all_images the way you want (i.e. descending)
all_images.sort (a, b) -> b.date - a.date
# render page and see that it works
res.render 'test.html', {images: all_images}

Resources