MongoDB date index - node.js

I am using node.js and mongodb for my small application and I want to index my document by date object. For Example
var MySchema = new Schema({
created_at: { type: Date, default: Date.now }
});
myschema.index({created_at: -1});
But how I understand, each object will have nearly unique create_id field. Wouldit work well ? and would this method give me effect. If you can, please also send me any articles about mongodb date indexing.

Related

How to insert Array of objects in mongoDB?

I am very new to MONGO DB so please bear with me.I am having a problem my array of objects is not working properly .
Here is my schema
const playerSchema = new mongoose.Schema({
name: String,
stats :{
wins:Number,
losses:Number,
xp:Number
},
achievement:[
{
name:String,
date: String
}
] });
Here is my document
const fluffy = new playerModel({
"name":"nic raboy",
"stats":{
"wins":5,
"losses":10,
"xp":300
},
"achievements":[
{"name":"Massive XP","date" :"25-08-21"},
{"name":"instant loss","date":"24-08-21"}
]
});
however in mongodb atlas its only showing array...and i cant see the objects inside...
SCREENSHOT
Your schema is correct, it seems your input is wrong,
In schema definition you named it achievement, whereas in input document it is achievements. Correct this everything will work as you expected.
Explanation
The schema is expecting achievement and you inserted achievements, that is why it is shown as an empty array in the database. To avoids this kind of typos in the future, use the required flag.
const playerSchema = new mongoose.Schema({
name: String,
stats: {
wins: Number,
losses: Number,
xp: Number
},
achievements: [
{
name: {
type: String,
required : true,
},
date: {
type: String,
required : true, // required informs for missing fields
}
}
]
})
Refer this link for more on validation
You can use insertMany see the doc here.
Of course, a while loop should work find calling multiple times insertOne, though I advise you to use the insertMany() method.
If you're new to MongoDB, I strongly encourage you to have a look at MongoDB University's MongoDB basics course as well as the MongoDB for JavaScript Developers course.

Proper way of updating average rating for a review system using Mongoose

I'm currently learning some backend stuff using an Udemy course and I have an example website that lets you add campgrounds (campground name, picture, description, etc.) and review them. I'm using the Express framework for Node.js, and Mongoose to access the database.
My campground schema looks like:
const campgroundSchema = new mongoose.Schema({
name: String,
image: String,
description: String,
price: String,
comments: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Comment"
}
],
rating: {type: Number, default: 0}
});
And my comment/review schema looks like:
const commentSchema = new mongoose.Schema({
text: String,
rating: {
type: Number,
min: 1,
max: 5,
validate: {validator: Number.isInteger}
},
campground: {type: mongoose.Schema.Types.ObjectId, ref: "Campground"}
});
Campgrounds and Comments also have references to a User but I've left that out for simplicity.
I'm looking to know the best practice for updating and displaying the campground average rating.
The method used by the tutorial I'm following is to recalculate the average rating each time a comment is added, changed, or deleted. Here's how it would work for a new comment:
Campground.findById(campgroundId).populate("comments").exec(function(err, campground) {
Comment.create(newComment, function(err, comment) {
campground.comments.push(comment);
campground.rating = calculateRating(campground.comments);
campground.save();
});
});
"calculateRating" iterates through the comment array, gets the total sum, and returns the sum divided by the number of comments.
My gut instinct tells me that there should be a way to make the "rating" field of Campground perform the functionality of the "calculateRating" function, so that I don't have to update the rating every time a comment is added, changed, or removed. I've been poking around documentation for a while now, but since I'm pretty new to Mongoose and databases in general, I'm a bit lost on how to proceed.
In summary: I want to add functionality to my Campground model so that when I access its rating, it automatically accesses each comment referenced in the comments array, sums up their ratings, and returns the average.
My apologies if any of my terminology is incorrect. Any tips on how I would go about achieving this would be very much appreciated!
Love,
Cal
I think what you are trying to do is get a virtual property of the document that gets the average rating but it does not get persisted to the mongo database.
according to mongoosejs :- Virtuals are document properties that you can get and set but that do not get persisted to MongoDB. They are set on the schema.
You can do this:
CampgroundSchema.virtual('averageRating').get(function() {
let ratings = [];
this.comments.forEach((comment) => ratings.push(comment.rating));
return (ratings.reduce((a,b)=>a+b)/ratings.length).toFixed(2);
});
After that on your view engine after finding campgrounds or a campground, all you need to call is ; campground.averageRating;
Read more here : https://mongoosejs.com/docs/guide.html#virtuals
also note that you can not make any type of query on virtual properties.

Using MomentJS for Default Date in MongoDB Document

I'm trying to use MomentJS to get non-localized UTC time and set that as the default for new documents created in Mongo.
var SubFavoriteSchema = new Schema({
user : { type: String, ref: 'Account'},
date : {type: Date, default: moment.utc()}
});
The problem is, moment.utc() returns the date that the Node server started. Thus if I start the server on Jan 1, all the documents get a UTC time of Jan 1, even if the document is created on Jan 10.
Any idea why it keeps getting the server's start time instead of the current time?
The problem is that you're calling the moment.utc() function (once) when creating the schema, so the same resulting value is used when creating new documents.
However, you don't need to use moment for this, default: Date.now will do what you want as that function returns the current UTC time. Note that you don't call the now function, you just pass the function itself. That's the key difference.
You need to use a factory function for that.
var currDate(){
return function(){
return moment.utc();
}
}
var SubFavoriteSchema = new Schema({
user : { type: String, ref: 'Account'},
date : {type: Date, default: currDate()}
});

Querying by date, regardless time part

I want to show my blog posts, paginated by creation date. I will have a page for 5 posts written in 2012-10-01, a page for 11 posts written in 2012-10-03 and no page at all for 2012-10-02 (no posts written)
Each post document is stored with a creation date which is a datetime value, here's a mongoose snippet:
var postSchema = new Schema({
url: String,
creationDate: {type: Date, default: Date.now},
contenuto: String,
});
so it will have something like 2012-10-01 18:45:03... know what I mean.
In my code, I will create a
var searchDate = new Date(yy,mm,dd);
How can I use that for querying the posts collection, without considering the "time part" of creationDate?
I'm not sure this would always work:
Post.find({ creationDate:dataRicerca })
As per this post;
How do I resolve a year/month/day date to a more specific date with time data in MongoDB?
you can store the data separately (as well as the full date) in your schema for easier searching. You could also do this;
Post.find({Posted:{$gt: Date("2012-10-01"), $lt:Date("2012-10-02")}})
(updated to use Date() rather than ISODate() for better compatibility)

is there a way to auto generate ObjectId when a mongoose Model is new'ed?

is there a way to declare a Model schema in mongoose so that when the model is new'ed the _id field would auto-generate?
for example:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ObjectIdSchema = Schema.ObjectId;
var ObjectId = mongoose.Types.ObjectId;
var PersonSchema = new Schema({
_id: ObjectIdSchema,
firstName: {type: String, default: 'N/A'},
lastName: {type: String, default: 'N/A'},
age: {type: Number, min: 1}
});
var Person = mongoose.model('Person', PersonSchema);
at first, i thought great!, i'll just do
_id: {type:ObjectIdSchema, default: new ObjectId()}
but of course that doesn't work, because new ObjectId() is only called on initialize of schema. so calling new Persion() twice creates two objects with the same _id value.
so is there a way to do it so that every time i do "new Person()" that a new ObjectId() is generated?
the reason why i'm trying to do this is because i need to know the value of the new person's _id value for further processing.
i also tried:
var person = new Person({firstName: "Joe", lastName: "Baz"});
person.save(function(err, doc, num){
console.log(doc._id);
});
even then, doc doesn't contain the ObjectId. but if i look in the database, it does contain it.
p.s. i'm using mongoose 2.7.1
p.p.s. i know i can manually create the ObjectId when creating the person as such:
var person = new Person({_id: new ObjectId(), firstName: "Joe", lastName: "Baz"});
but i rather not have to import ObjectId and have to new it every time i want to new a Person. guess i'm used to using the java driver for mongodb, where i can just create the value for the _id field in the Model constructor.
Add the auto flag:
_id: {
type: mongoose.Schema.Types.ObjectId,
index: true,
required: true,
auto: true,
}
source
the moment you call var person = new Person();
person._id should give you the id (even if it hasn't been saved yet). Just instantiating it is enough to give it an id. You can still save it after, and that will store the id as well as the rest of the person object
Instead of:
_id: {type:ObjectIdSchema, default: new ObjectId()}
You should do:
_id: {type:ObjectIdSchema, default: function () { return new ObjectId()} }
Taken from the official MongoDB Manual and Docs:
_id
A field required in every MongoDB document. The _id field must have a
unique value. You can think of the _id field as the document’s primary
key. If you create a new document without an _id field, MongoDB
automatically creates the field and assigns a unique BSON ObjectId.
Source
ObjectID
ObjectIds are small, likely unique, fast to generate, and ordered.
ObjectId values consist of 12 bytes, where the first four bytes are a
timestamp that reflect the ObjectId’s creation. Specifically:
a 4-byte value representing the seconds since the Unix epoch, a 5-byte
random value, and a 3-byte counter, starting with a random value. In
MongoDB, each document stored in a collection requires a unique _id
field that acts as a primary key. If an inserted document omits the
_id field, the MongoDB driver automatically generates an ObjectId
for the _id field.
This also applies to documents inserted through update operations with
upsert: true.
MongoDB clients should add an _id field with a unique ObjectId.
Using ObjectIds for the _id field provides the following additional
benefits: in the mongo shell, you can access the creation time of the
ObjectId, using the ObjectId.getTimestamp() method. sorting on an _id
field that stores ObjectId values is roughly equivalent to sorting by
creation time. IMPORTANT While ObjectId values should increase over
time, they are not necessarily monotonic. This is because they:
Only contain one second of temporal resolution, so ObjectId values
created within the same second do not have a guaranteed ordering, and
Are generated by clients, which may have differing system clocks.
Source
Explicitly declaring _id:
When explicitly declaring the _id field, specify the auto option:
new Schema({ _id: { type: Schema.ObjectId, auto: true }})
ObjectId only - Adds an auto-generated ObjectId default if turnOn is true.
Source
TL;DR
If you create a new document without an _id field, MongoDB automatically creates the field and assigns a unique BSON ObjectId.
This is good way to do this
in model:
const schema = new Schema({ userCurrencyId:{type: mongoose.Schema.Types.ObjectId,
index: true,
required: true,
auto: true});

Resources