Is there a way to edit mongo db sorting? - node.js

I have a mongoose collection that sorts by first added, and I want it to sort by last edited
The model
var mongoose = require("mongoose");
var user = require("./user");
var questionSchema = new mongoose.Schema({
text: String,
asked: String,
answer: String
})
module.exports = mongoose.model("question", questionSchema);
The put request code:
router.put("/:user/:id", checkOwner, function(req, res){
question.findByIdAndUpdate(req.params.id, req.body.question, function(err,
updatedQuestion){
if(err) {
console.log(err);
} else {
res.redirect("/");
}
});
});
I want that updatedQuestion to be on the top my collection

Here is one simple approach:
First you have to add timestamps in your mongoose model, in order to have access on createdAt and updatedAt proerties.
You can see more about timestamps here
var mongoose = require("mongoose");
var user = require("./user");
var questionSchema = new mongoose.Schema({
text: String,
asked: String,
answer: String
},
{ timestamps: true}
)
module.exports = mongoose.model("question", questionSchema);
Then you can query your collections, applying sorting by updatedAt
question.find({}, {}, {sort: { 'updatedAt' : -1 }})
Thus the most recent updated document will be shown first.

Related

MongoError: E11000 duplicate key error

i'm making a simple blog app using nodejs + express, i can add first post without a problem but when i try to add second post i got his error { MongoError: E11000 duplicate key error collection: restful_blog_app_v2.blogs index: username_1 dup key: { : null }
this is my schema
var mongoose = require("mongoose");
var passportLocalMongoose = require("passport-local-mongoose");
var BlogSchema = new mongoose.Schema({
title: String,
image: String,
body: String,
created: {
type: Date,
default: Date.now
},
author: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
username: String
}
});
BlogSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model("Blog", BlogSchema);
this is the user schema
var mongoose = require("mongoose");
var passportLocalMongoose = require("passport-local-mongoose");
var UserSchema = new mongoose.Schema({
username: String,
password: String,
});
UserSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model("User", UserSchema);
this is the create new post route
app.post("/blogs", isLoggedIn, function (req, res) {
req.body.blog.body = req.sanitize(req.body.blog.body);
var title = req.body.blog.title;
var image = req.body.blog.image
var body = req.body.blog.body;
var created = req.body.blog.created;
var author = {
id: req.user._id,
username: req.user.username
}
var newPost = {
title: title,
image: image,
body: body,
created: created,
author: author
}
Blog.create(newPost, function (err, newBlog) {
if (err) {
console.log(err);
res.render("new");
} else {
console.log(newBlog);
res.redirect("/blogs");
}
});
});
I've tried to dropped the entire database using db.dropDatabase() from the mongo console but the problem still persist, not sure what to do now
This is caused by passport-local-mongoose, which, according to its fine manual, makes username a unique field by default.
You have added this plugin to BlogSchema, which seems like you initially had the user data in that schema but moved it to a separate schema (UserSchema) and forgot to remove it from the former.
Start by not using it for BlogSchema, and you also need to drop the unique index on username on the blogs collection.
Can you try deleting your Schema and again send the value? I was getting the same issues. I solved with the above idea.

Mongoose - inserting subdocuments

I have a user model, and a log model. The log model is a subdocument of user model. So in my user model I have:
var mongoose = require('mongoose');
var Log = require('../models/log');
var UserSchema = new mongoose.Schema({
username: {
type: String,
unique: true
},
logsHeld: [
Log
]
});
Then in my 'Log' model I have:
var mongoose = require('mongoose');
var logSchema = new mongoose.Schema({
logComment: {
type: String,
},
});
module.exports = mongoose.model('Log', logSchema);
So upon creation of a 'user', the 'logsHeld' always begins empty. I want to know how to add subdocuments to this user model.
I've tried doing this POST method:
router.post('/createNewLog', function(req, res) {
var user = new User ({
logssHeld: [{
logComment: req.body.logComment
}]
});
user.save(function(err) {
if(err) {
req.flash('error', 'Log was not added due to error');
return res.redirect('/home');
} else {
req.flash('success', 'Log was successfully added!');
return res.redirect('/home');
}
});
});
But this doesn't work. It also includes a 'new User' line, which I don't think I need given this would be for an existing user.
You need to use the logSchema instead of the Log model as your subdocument schema in User model. You can access the schema as follows:
var mongoose = require('mongoose');
/* access the Log schema via its Model.schema property */
var LogSchema = require('../models/log').schema; // <-- access the schema with this
var UserSchema = new mongoose.Schema({
username: {
type: String,
unique: true
},
logsHeld: [LogSchema]
});
Picking up from your comments in another answer where you are facing another issue
WriteError({"code":11000,"index":0,"errmsg":"E11000 duplicate key
error index: testDB.users.$email_1 dup key:
you are getting this because there's already a document in your users collection that has most probably a null value on the email field. Even though your schema does not explicitly specify an email field, you may have an existing old and unused unique index on users.email.
You can confirm this with
testDB.users.getIndexes()
If that is the case and manually remove the unwanted index with
testDB.users.dropIndex(<index_name_as_specified_above>)
and carry on with the POST to see if that has rectified the error, I bet my $0.02 that there is an old unused unique index in your users collection which is the main issue.
Try using logSchema which references only the subdocument schema, Log refers to the entire contents of ../models/log
var UserSchema = new mongoose.Schema({
username: {
type: String,
unique: true
},
logsHeld: [
logSchema
]
});
Documentation: http://mongoosejs.com/docs/subdocs.html
Try push to insert item in array in mongoose
var user = new User;
user.logssHeld.push({
logComment: req.body.logComment
});
user.save(function(err, doc) {
//DO whatever you want
});
see the docs here

MongoDB with Mongoose aggregate data

I have problems with aggregating data:
//create a schema
var userSchema = new Schema (
{
Anzahl: Number,
Art: String,
Gewicht: Number,
Strecken_ID: Number,
}, {collection: 'kkr'});
//model
var User = db.model('User', userSchema);
//test aggregate
app.get('/gesamt', function(req,res){
User.aggregate([{"$match": {Art: "Aal"}}], function(err, docs){
if(err){console.log(err);}
else {res.json(docs);}
});
});
This delivers an empty array []; what ist the reason?
Any help would be great.
Best
Hucho
[] means there is no documents with value Art: "Aal" in kkr collection.

mongoose not retrieving _id

I am trying to find a document from mongo, but the findOne() brings the document with an undefined _id field.
why?
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/school');
var Schema = mongoose.Schema;
var scoreSchema = new Schema({
type: String,
score: Number
});
var studentSchema = new Schema({
name: String,
scores: [scoreSchema]
});
var mod = mongoose.model('Student', studentSchema);
mod.findOne(function(err, stud) {
console.log('id:' + stud._id);
});
You need to pass something to find in your query. For example:
mod.findOne({name: 'John'}, function(err, stud) {
console.log('id:' + stud._id);
});
See here on how to make queries in Mongoose.
You're not querying anything, notice the {} before the callback.
mod.findOne({}, function(err, stud) {
console.log('id:' + stud._id);
});
You might want to have a look at the Mongoose documentation.

How to set ObjectId as a data type in mongoose

Using node.js, mongodb on mongoHQ and mongoose. I'm setting a schema for Categories. I would like to use the document ObjectId as my categoryId.
var mongoose = require('mongoose');
var Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
var Schema_Category = new Schema({
categoryId : ObjectId,
title : String,
sortIndex : String
});
I then run
var Category = mongoose.model('Schema_Category');
var category = new Category();
category.title = "Bicycles";
category.sortIndex = "3";
category.save(function(err) {
if (err) { throw err; }
console.log('saved');
mongoose.disconnect();
});
Notice that I don't provide a value for categoryId. I assumed mongoose will use the schema to generate it but the document has the usual "_id" and not "categoryId". What am I doing wrong?
Unlike traditional RBDMs, mongoDB doesn't allow you to define any random field as the primary key, the _id field MUST exist for all standard documents.
For this reason, it doesn't make sense to create a separate uuid field.
In mongoose, the ObjectId type is used not to create a new uuid, rather it is mostly used to reference other documents.
Here is an example:
var mongoose = require('mongoose');
var Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
var Schema_Product = new Schema({
categoryId : ObjectId, // a product references a category _id with type ObjectId
title : String,
price : Number
});
As you can see, it wouldn't make much sense to populate categoryId with a ObjectId.
However, if you do want a nicely named uuid field, mongoose provides virtual properties that allow you to proxy (reference) a field.
Check it out:
var mongoose = require('mongoose');
var Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
var Schema_Category = new Schema({
title : String,
sortIndex : String
});
Schema_Category.virtual('categoryId').get(function() {
return this._id;
});
So now, whenever you call category.categoryId, mongoose just returns the _id instead.
You can also create a "set" method so that you can set virtual properties, check out this link
for more info
I was looking for a different answer for the question title, so maybe other people will be too.
To set type as an ObjectId (so you may reference author as the author of book, for example), you may do like:
const Book = mongoose.model('Book', {
author: {
type: mongoose.Schema.Types.ObjectId, // here you set the author ID
// from the Author colection,
// so you can reference it
required: true
},
title: {
type: String,
required: true
}
});
My solution on using ObjectId
// usermodel.js
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const ObjectId = Schema.Types.ObjectId
let UserSchema = new Schema({
username: {
type: String
},
events: [{
type: ObjectId,
ref: 'Event' // Reference to some EventSchema
}]
})
UserSchema.set('autoIndex', true)
module.exports = mongoose.model('User', UserSchema)
Using mongoose's populate method
// controller.js
const mongoose = require('mongoose')
const User = require('./usermodel.js')
let query = User.findOne({ name: "Person" })
query.exec((err, user) => {
if (err) {
console.log(err)
}
user.events = events
// user.events is now an array of events
})
The solution provided by #dex worked for me. But I want to add something else that also worked for me: Use
let UserSchema = new Schema({
username: {
type: String
},
events: [{
type: ObjectId,
ref: 'Event' // Reference to some EventSchema
}]
})
if what you want to create is an Array reference. But if what you want is an Object reference, which is what I think you might be looking for anyway, remove the brackets from the value prop, like this:
let UserSchema = new Schema({
username: {
type: String
},
events: {
type: ObjectId,
ref: 'Event' // Reference to some EventSchema
}
})
Look at the 2 snippets well. In the second case, the value prop of key events does not have brackets over the object def.
You can directly define the ObjectId
var Schema = new mongoose.Schema({
categoryId : mongoose.Schema.Types.ObjectId,
title : String,
sortIndex : String
})
Note: You need to import the mongoose module
Another possible way is to transform your _id to something you like.
Here's an example with a Page-Document that I implemented for a project:
interface PageAttrs {
label: string
// ...
}
const pageSchema = new mongoose.Schema<PageDoc>(
{
label: {
type: String,
required: true
}
// ...
},
{
toJSON: {
transform(doc, ret) {
// modify ret directly
ret.id = ret._id
delete ret._id
}
}
}
)
pageSchema.statics.build = (attrs: PageAttrs) => {
return new Page({
label: attrs.label,
// ...
})
}
const Page = mongoose.model<PageDoc, PageModel>('Page', pageSchema)
Now you can directly access the property 'id', e.g. in a unit test like so:
it('implements optimistic concurrency', async () => {
const page = Page.build({
label: 'Root Page'
// ...
})
await page.save()
const firstInstance = await Page.findById(page.id)
const secondInstance = await Page.findById(page.id)
firstInstance!.set({ label: 'Main Page' })
secondInstance!.set({ label: 'Home Page' })
await firstInstance!.save()
try {
await secondInstance!.save()
} catch (err) {
console.error('Error:', err)
return
}
throw new Error('Should not reach this point')
})

Resources