Indexing mongoose timestamps - mongodb

I have a mongoose schema like so:
let PictureSchema = mongoose.Schema({
...
...
}, {timestamps: true})
PictureSchema.index({"createdAt": 1});
PictureSchema.index({"updatedAt": 1});
I'm trying to get the fields "createdAt" and "updatedAt" indexed. When using
PictureSchema.index({"createdAt": 1});
PictureSchema.index({"updatedAt": 1});
It doesn't work and all other indexes except "_id_" also stop working.
I got a variation of this working by using the mongoose-timestamp plugin like so:
PictureSchema.plugin(timestamps, {
createdAt: {
name: 'createdAt',
type: Date,
index: true
},
updatedAt: {
name: 'updatedAt',
type: Date,
index: true
}
})
But the problem I have with this plugin is that it doesn't record UTC time but system time. A fix to my problem would also be to get mongoose-timestamp to record UTC time but preferably I would prefer to index the fields provided by the built in timestamps.

Turns out
PictureSchema.index({"createdAt": 1});
PictureSchema.index({"updatedAt": 1});
Works perfectly. Had to restart the database server a couple of times to get it working.
Wondering why is that?

Related

Indexing has no effect on db.find()

I've Just started to work with MongoDB, so you might find my question really stupid.I tried to search a lot before posting my query here, Any Help would be Appreciated.
I also came across this link StackOverFlow Link, which advised to apply .sort() on every query, but that would increase the query time.
So I tried to index my collection using .createIndexes({_id:-1}), to sort data in descending order of creation time(newest to oldest), After that when I used the .find() method to get data in sorted format(newest to Oldest) I did'nt get the desired result , I still had to sort the data :( .
// connecting db
mongoose.connect(dbUrl, dbOptions);
const db = mongoose.connection;
// listener on db events
db.on('open', ()=>{console.log('DB SUCESSFULLY CONNECTED !!');});
db.on('error', console.error.bind(console, 'connection error:'));
// creating Schema for a person
const personSchma = new mongoose.Schema(
{ name: String,
age : Number}
)
// creating model from person Schema
const person = mongoose.model('person', personSchma);
// Chronological Order of Insertion Of Data
// {name: "kush", age:22}
// {name: "clutch", age:22}
// {name: "lauv", age:22}
person.createIndexes({_id:-1}, (err)=>{
if (err){
console.log(err);
}
})
person.find((err, persons)=>{
console.log(persons)
// Output
// [
// { _id: 6026eadd58a2b124d85b0f8d, name: 'kush', age: 22, __v: 0 },
// { _id: 6026facdf200f8261005f8e0, name: 'clutch', age: 22, __v: 0 },
// { _id: 6026facdf200f8261005f8e1, name: 'lauv', age: 22, __v: 0 }
// ]
})
person.find().sort({_id:-1}).lean().limit(100).then((persons)=>{
console.log(persons);
// Output
// [
// { _id: 6026facdf200f8261005f8e1, name: 'lauv', age: 22, __v: 0 },
// { _id: 6026facdf200f8261005f8e0, name: 'clutch', age: 22, __v: 0 },
// { _id: 6026eadd58a2b124d85b0f8d, name: 'kush', age: 22, __v: 0 }
// ]
})
Indexes are special data structure, which can be used to run the queries efficiently. While running the query, MongoDB tries to see which index should be used for running the query efficiently and then that index will be used.
Creating an index with {_id:-1} will create an auxiliary data structure(index) which will be sorted newest first. It doesn't affect the order of the data which we are storing.
To sort the data in descending order(newest first) we will have to explicitly add the sort operation in your query and make sure that an index for descending order _id is present.

Nested JSON output from mongodb via Get

I have some status-Data from a bunch of devices stored in mongoDB and I like to aggregate via mongoose some simple statistics pending on input variables e.g. input about timespan (start to end).
Plane Dataset in mongoDB looks somehowe like this:
{
"_id":"5d65b4a9cef78a5c987b2224",
"Date":"2019-08-01T00:00:00.000Z",
"Id":9,
"StandingNoMovement":21.9,
"DrivingHours":0.4,
"StandingWithEngineOn":1.6
},
{
"_id":"5d65b4a9cef78a5c987b2225",
"Date":"2019-08-02T00:00:00.000Z",
"Id":9,
"StandingNoMovement":19.2,
"DrivingHours":2.3,
"StandingWithEngineOn":2.3,
}
and I need to create a GET for an API with the structure of
[{"Id":9,
"DrivingHours":
{"Total":276.9,"Day":0.0,"ThisWeek":0.0,"ThisMonth":0.0},
"StandingNoMovement":
{"Total":678.4,"Day":0.0,"ThisWeek":0.0,"ThisMonth":0.0},
"StandingWithEngineOn":
{"Total":521.4,"Day":0.0,"ThisWeek":0.0,"ThisMonth":0.0}]
So fare, I only managed to aggregate some not nestet statistics in mongoose like:
const aggReport = mongoose.model('aggReport', aggReportingSchema);
aggReport.aggregate([
{ $match:
{ Id : req.params.Id ,'Date': { $gte: start, $lt: end}
}
},
{ $group:
{ _id: null,
'DrivingHours': {$sum: '$DrivingHours'},
'StandingWithEngineOn': {$sum: '$StandingWithEngineOn'},
'StandingNoMovement': {$sum: '$StandingNoMovement'}
}
}])
on the Schema
export const aggReportingSchema = new Schema({
Id:{ type: Number},
Date:{ type: Date},
StandingNoMovement:{ type: Number},
StandingWithEngineOn:{ type: Number},
},{ collection : 'status_daily' });
How to get the nested statistics as they look that simple to me?
I just switched now to a total different approach, as I got the impression, that there are no proper and usable solutions (perhaps with good reasons) to dynamically create such a API. So now I store all the date precalculated in the mondodb and I am using express and node just to call the necessary dataset.

Mongo collection structure migration

I'm a relative newcomer to Mongodb and I've hit a situation that I don't quite see how I resolve. I have this field definition in a mongoose schema:
account_number: {
type: String,
index: false,
required: false
},
Which I am converting to
account_number: [
{
type: String,
index: false,
required: false
}
],
Which is fine, the point I am stuck on is now converting the data still held in the previous definition into the new array format. How would I do this on the command line?
Edit:
I have this now:
db.customers.find().snapshot().forEach(function (elem) {
db.customers.update({_id: elem._id},{$unset: {account_number: 1}});
db.customers.update({_id: elem._id},{$push: {account_number: elem.account_number}});});
Which is recreating the property as an array, but it is blank.
OK so this is what I got working:
db.customers.find().forEach(function (elem) {
db.customers.update({_id: elem._id}, {$unset: {account_number: 1}});
db.customers.update({_id: elem._id}, {$push: {account_number: elem.account_number}});
});
For anyone who finds this

Why does this query of a nested object not work?

Given this Job object structure, where users is an array of user documents:
{
_id: "56228b5ba851623018f88ff7",
created: "2015-10-17T17:54:35.475Z",
active: true,
workOrders: [{
startDate: "2015-10-18T05:00:00.000Z",
name: "Test1",
users: [{...}]
},{
startDate: "2015-10-20T05:00:00.000Z",
name: "Test2",
users: [{...}]
}]
}
Why does this query work:
Job.find({
'workOrders.users._id' : userId,
'created' : { '$gte' : new Date('10/17/2015'), '$lt': new Date('10/25/2015')},
'active' : true
}).exec(cb);
But this one does not:
Job.find({
'workOrders.users._id' : userId,
'workOrders.startDate' : { '$gte' : new Date('10/20/2015'), '$lt': new Date('10/25/2015')},
'active' : true
}).exec(cb);
Initial thought is that workOrder.startDate is not of type date, but it is.
Is there some reason I cannot query the nested workOrder object this way? I'm just confused why I can query the created date property on the Job document, I can query the array of nested user documents in the workOrders array, but then this last query doesn't work.
Note, there are no errors thrown, it simply returns no results. Even if I expand the date range to definitely be inclusive of all dates such as 01/01/2000 to 01/01/2016 I get nothing.
Can you replace both startDate's with:
created: {
type: Date,
default: Date.now
},
...to establish whether you can add multiple dates to a document, and that your startDate code is not incorrect?

Get newest object of each subset

I'm working on an app based on mongodb and mongoose. One of my schemas has the following form:
var schema = new mongoose.Schema(
{
name: { type: String },
timestamp: { type: Number, default: Date.now },
// further properties
});
schema.index({ name: 1, timestamp: -1 });
I'd like to retrieve the newest object (i.e., largest timestamp) for a set of name-strings.
E.g., consider the set of names ['a','b']. How do I query the database such that I get returned a collection of objects that contains both, the newest entry where id=='a', and the newest entry where id=='b'?
[Update: The idea is to avoid having to query the database multiple times (i.e. once for each name).]
"How do I query the database such that I get returned a collection of objects that contains the newest where id=='a'"
db.collection.find({ name : 'a' }).sort({ timestamp : -1 })
"and the newest entry where id=='b'?"
db.collection.find({ name : 'b' }).sort({ timestamp : -1 }).limit(1)