I started taking some tutorials and some books about NodeJS, and started to test out stuff using Mongoose and Rest API requests.
The problem that I encountered is related to the creation of a constructor which will take a parameter (requestBody) and then implement the whole binding on the module (on my case user.js). That is to make the code more reusable and the user module to handle the bindings not the server module which will increase the source code a lot there.
Example
The code below is working as it should, but it's not efficient
var express = require('express')
, bodyParser = require('body-parser')
, expressValidator = require('express-validator')
, mongoose = require('mongoose');
var router = express.Router();
router.route('/users')
// Create a user (accessed at POST http://localhost:8080/api/users)
.post(function (req, res) {
// Bind user (repeating the same procedure for every User object)
var user = new User();
user.info.name = req.info.name;
user.info.surname = req.info.name;
.... // around 10 other properties
req.info.birthday = req.info.name;
// Save
user.save(function (err) {
.... // Handling completion
});
})
My approach
// app/models/user.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var userSchema = new Schema({
info: {
name: {type: String, required: true},
surname: {type: String, required: true},
......
birthday: {type: String, required: true}, // dd/mm/yyyy
},
likes: [Schema.Types.ObjectId],
dislikes: [Schema.Types.ObjectId]
});
function initUser(model) {
userSchema.info.name = model.info.name;
userSchema.info.surname = model.info.surname;
......
userSchema.info.birthday = model.info.birthday;
userSchema.likes = model.likes;
userSchema.dislikes = model.dislikes;
}
module.exports = mongoose.model('User', userSchema);
module.exports.initUser = initUser;
Based on this code, on the request I could easily use (Javascript beginner so explanation will be great)
var user = new User();
user.initUser(req);
but I come up with a really long error which causes the server to crash and the cleanest message is:
TypeError: Converting circular structure to JSON
Questions
Is there anyone who has solved this? I also took a look at Mongoose site, but there doesn't seem to have a specific thing like this.
I'm not sure about your circular json problem, but your initial problem is the way in which you are reading your model properties off your request.
If you post values to that endpoint, the json values you are looking for are going to be on the body property on the request. Pass your function this:
user.initUser(req.body)
You'll need to install a body parser in express to handle the value properly. Once you've done that and pass in request.body, your approach will work.
Pro tip: don't bother mapping the properties individually. If the keys are correctly named just use them to construct your model directly.
Related
I am working on a wiki-like website component and I am trying to implement a fuzzy search. I found a popular Node.js plugin on npmjs for a fuzzy search of a cloud mongoDB database handled with Mongoose. I installed and saved mongoose-fuzzy-searching and hooked it up to my model and route. Then I updated all of the models, resaving each's value for the field I wanted to index. I can seem to call the function on a model, and it seems like there's an index on MongoDB Atlas, but it returns an empty array instead of any results. 2 questions:
Am I doing something wrong, or is there something I am missing?
Is there a better node library that's free? (*Free on heroku, which I think eliminates flexsearch as an option)
Here's my code.
Model:
const mongoose = require("mongoose"),
mongoose_fuzzy_searching = require('mongoose-fuzzy-searching'),
Schema = mongoose.Schema;
const IssueTemplateSchema = new Schema({
name: String,
info: String,
image: String,
tags: [{type: Schema.Types.ObjectId, ref: "Tag"}],
active: {type: Boolean, default: true},
instances: [{type: Schema.Types.ObjectId, ref: "LocalIssue"}],
issues: {type: Schema.Types.ObjectId, ref: "Issuegraph" },
});
IssueTemplateSchema.plugin(mongoose_fuzzy_searching, { fields: ['name'] });
module.exports = mongoose.model("IssueTemplate", IssueTemplateSchema);
An update to all of the issuetemplate models:
const express = require('express'),
router = express.Router(),
Issue = require('../api/issue/issue.template');
router.get("/createIndex", async (req, res) => {
Issue.find({}, async (err, issues) => {
if(err){console.log(err)}else {
for(issue of issues){
if(err){console.log(err)}else{
const name = issue.name;
await Issue.findByIdAndUpdate(issue._id, {name: name}, {strict: false});
}
}
}
});
return res.send("done");
});
Route:
router.get("/search", (req, res) => {
console.log(req.query.target);
let searchTerm = "";
if(req.query.target){
searchTerm = decodeURIComponent(req.query.target.replace(/\+/g, ' '));
}
Issue.fuzzySearch(searchTerm, (err, issue)=> {
if(err){
console.log(err);
res.send("Error fuzzy searching: " + err);
} else {
returnResult(issue);
}
});
function returnResult(result) {
console.log(result);
return res.send(result);
}
});
When I ran
npm install --save mongoose-fuzzy-searching
I received an error saying it needed mongoose 5.10, and I have 5.11, but it seemed to at least plug in. Can't see why When I send a request through Postman, I receive an empty array. If I leave the query blank, then I get everything. I have reset Node and am using mongoDB Cloud, where I see an index has been created. Is there perhaps a reset of the cloud database I would need to do (I don't know of such a thing), or is resetting the server enough? My knowledge level is: studying to be a freelance web developer and would appreciate any general tips on best practice, etc.
Mongoose need to define schema. which makes it slow and find() method is good for development, not for production level. Also ,This Process is outdated. You are working on MongoDB. if you need search then take a look into MongoDB atlas Full Text-Search.It includes all of those searching features like: autocomplete, Fuzzy Search everything.
It seems like my update operation was not actually updating the field I wanted to update, because findByIdAndUpdate() returns a query and I wasn't executing that query (with .exec() ). Await was also being used incorrectly because its purpose is not just to pause in an async function like I thought, but to wait for a promise to fulfill. A query is not a promise, and await is specifically for promises. Before I learned these details, I solved my problem in another way by using .find() , then .markModified("name") , then .save() . Once I did that, it all worked!
I have a problem and could really use some help.
We had an application that used MySQL and we are switching over to MongoDB.
We are using Node.js with Express and have MongoDB and Mongoose for the database
We have looked at the MongoDB and Mongoose documentation and searched for related questions on Stack Overflow but we seem to be missing something.
This is what we have in app.js:
var mongo = require('mongodb');
var mongoose = require('mongoose');
var db = mongoose.connect('mongodb://localhost:27017/DBName');
This is our usersModel.js
var db = require('mongoose');
var Schema = db.Schema;
var userSchema = new Schema({
u_id : Number,
u_name : { type: String, required: true },
u_lastname : String
});
module.exports = db.model('user', userSchema);
And this is what we use in the userController:
var User = require('../models/usersModel');
User.find({}, function(err, users) {
if (err) throw err;
console.log("Found users: ", users);
});
The console.log(db.connection.readyState); says it is connecting.
And the User.find() doesn't seem to give out an error, but instead gives an empty array/undefined.
We would really appreciate it if someone could tell us what we overlook.
Thanks in advance.
Not sure why anyone thought this was a good idea, but here's what mongoose does:
Mongoose by default produces a collection name by passing the model name to the utils.toCollectionName method. This method pluralizes the name.
As a bonus, it's in lower-case which sucks when you have table names with camel case convention.
You can fix it by setting below option in your scheme:
var userSchema = new Schema({..}, { collection: 'user' });
More on this here.
Your find() call looks fine to me.
Are you sure there are users in your collection? Does creating a new user throw an error that you didn't notice? Maybe you can verify that there are indeed users in your collection by popping open a terminal and writing:
> mongo
> use DBName
> show collections
> db.user.find()
And that will return all users that exist.
At: iuliu.net: We get both errors the first was [] and the second is undefined.
At JohnnyHK: Thank you for your submit, but we are sure the the user collection is in this database and the properties we search exists.
At Juuso: Thanks for your feedback your but in the mongo terminal we got the collection output.
Some one asked us a critical question if we tried this with monk. We
installed monk and we have find the database, collection and got
result back. We're still not sure what the problem with Mongoose was,
but with monk it works.
Thank you guys for your feedback and time.
Ok so after a ton of trial and error, I've determined that when I drop a collection and then recreate it through my app, unique doesn't work until I restart my local node server. Here's my Schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var Services = new Schema ({
type : {type : String},
subscriptionInfo : Schema.Types.Mixed,
data : Schema.Types.Mixed
},{_id:false});
var Hashtags = new Schema ({
name: {type : String},
services : [Services]
},{_id:false});
var SubscriptionSchema = new Schema ({
eventId : {type: String, index: { unique: true, dropDups: true }},
hashtags : [Hashtags]
});
module.exports = mongoose.model('Subscription', SubscriptionSchema);
And Here's my route...
router.route('/')
.post(function(req, res) {
var subscription = new subscribeModel();
subscription.eventId = eventId;
subscription.save(function(err, subscription) {
if (err)
res.send(err);
else
res.json({
message: subscription
});
});
})
If I drop the collection, then hit the /subscribe endpoint seen above, it will create the entry but will not honor the duplicate. It's not until I then restart the server that it starts to honor it. Any ideas why this is? Thanks!
What mongoose does when your application starts and it itself initializes is scan your schema definitions for the registered models and calls the .ensureIndexes() method for the supplied arguments. This is the "by design" behavior and is also covered with this statement:
When your application starts up, Mongoose automatically calls ensureIndex for each defined index in your schema. While nice for development, it is recommended this behavior be disabled in production since index creation can cause a significant performance impact. Disable the behavior by setting the autoIndex option of your schema to false.
So your general options here are:
Don't "drop" the collection and call .remove() which leaves the indexes intact.
Manually call .ensureIndexes() when you issue a drop on a collection in order to rebuild them.
The warning in the document is generally that creating indexes for large collections can take some time and take up server resources. If the index exists this is more or less a "no-op" to MongoDB, but beware of small changes to the index definition which would result in creating "additional" indexes.
As such, it is generally best to have a deployment plan for production systems where you determine what needs to be done.
This post seems to argue that indexes are not re-built when you restart: Are MongoDB indexes persistent across restarts?
Im building a simple web app app in express, and I'm a bit stuck in the authentification for my sessions, im going to validate everything in the client with backbone and regExp eventually when i start building the front end of the app. no basycally i have an issue with the query in mongoose returning a mongoose document object. I've looked up a couple of solutions, in the query you can use a .lean() to get an object, or grab the return from the query and apply a .toObject(), that all works fine and dandy, however when i try and authenticate the value of the key with a string it returns false. i'll post an example code, its not exactly what i've got, but its close enough to get the point across.
this would be an example of my models file
var User = new Schema({}, { strict: false });
User.method('authenticate', function(plainText) {
var object = this.toObject();
return plainText == object.password; });
mongoose.model('User', User);
mongoose.connect( definitions.dbConnect );
and in my app file i would have something like
app.get('/session', routes.showLogin);
app.post('/session/new', routes.login);
and in my routes file id have something like
exports.login = function(req, res){
var userQuery = new RegExp(req.body.username , 'i');
var passwordQuery = new RegExp(req.body.password, 'i');
var Query = User.find();
Query.findOne().where('username', userQuery).exec(function(err, user){
if(user && user.authenticate((req.body.password))){
req.session.userId = user._id;
}else{
res.redirect('/session');
}
});
},
Any ideas would be appreciated, its probably very silly... : /
Thanks in advanced!
YEah robert klep was right on the money, After i seearched the mongoose Documentation and the mongodb docs as well, it became clear that queries return a mongo document object, in terms should be converted to the same object or variable types for opperands to work.
I am currently working on a small personal multiplayer game project. I am using node.js along with express.js, mongoose and socket.io. It is my first project with JavaScript, I come from a C/C++ background.
The question is:
Whether some kind of generic requiring is possible:
I have currently a models folder in my project root and all the mongoose models are in there,
they all look similar to this one:
function make(Schema, mongoose) {
var UserSchema = new Schema({
name : String
, passwd : String
, is_online : Boolean
, socket_id : Number
});
mongoose.model('User', UserSchema);
}
module.exports.make = make;
If I remember right, I found this approach somewhere on stackoverflow. Now when I am starting the node.js application, I have to connect to the database and then have to call all the make functions.
Is there a generic way to do that?
Somethink like this (pseudo-code):
models = require('./models/');
for each m in models do
{
m.make(Schema, mongoose);
}
I do it a little different:
var UserSchema = new Schema({
name : String
, passwd : String
, is_online : Boolean
, socket_id : Number
});
module.exports = mongoose.model('User', UserSchema);
Now I can require the model and use it right away like this:
var userModel = require('models/user');
userModel.find()//...