I am trying to generate Mongoose compliant ObjectId's on a NextJs frontend. The thing is though, the minute you import mongoose to try use the good-ol' const ObjectId = mongoose.Types.ObjectId; then const _id = new ObjectId(); 'maneuver' it immediately throws a TypeError: t.versions.node is undefined error in my case (very hard to debug the first time.. I was optimist it would work maybe this time doing some refactoring a few months later... But the minute I tried like oil in water.).
import mongoose from 'mongoose';
// and
const mongoose = require('mongoose');
Give the same error.
Is there a better way to create it? Other systems rely on this being a valid Id i.e. not just the same alphaNumeric length.
Less of a performance hit than creating a NextJs API GET route that just returns my backend shenanigans as a simple string (a network request?).
P.S. Use TypeScript if that could mean anything.. Also using Vercel (which has also caused build problems in the past)
I was too stuck in looking for a NextJs solution in my searches when it is still Javascript and React at the end of the day. This thread had the answer:
npm i bson
then
import { ObjectID } from 'bson';
const id = new ObjectID();
Works perfectly in NextJs as well as my Mongo/Mongoose database.
Related
I recently used nestjs, But I realized its overcomplicated, I mean look the following code:
#post('/products')
getAllProducts(#Body('title') title, #Body('price') price, #Body('description') description) { }
It makes function parameters much dirty, Also there could be more decorators above function like #Header, #Params, etc.. Which reduces readability in my opinion.
Same code in nodejs
const { title: title, price: price, description: description } = req.body
nodejs is much more readable...
Then I researched why developers use nestjs, Reason was Modularity. Why we don't implement this on our own...
See below:
See my directory sutructure
In app.js I just kicked the app:
const express = require('express');
const app = express();
// express config
require('./startup/config')(app);
// handling routes
require('./startup/routes')(app);
// db setup
require('./startup/db')(app);
In startup folder I did the basic work like mongoose configuration and connection to db etc..
However, In startup/routes, I just kicked the module as follow:
const shopModule = require('../shop/shop.module');
module.exports = app => {
app.use('/', shopModule);
};
In shop module, I just kicked the routes as follow:
const router = require('express').Router();
const productsRouter = require('./products/index');
const cartRouter = require('./cart/index');
// Products
router.use('/products', productsRouter)
// Cart
router.use('/cart', cartRouter)
module.exports = router;
Now in cart/index.js, I handled the routes related to cart and same for products as follow (I will just show cart):
const router = require('express').Router();
const { getCart } = require('./cart.controller');
router.get('/', getCart);
module.exports = router;
In controller, basically we will do validation stuff etc or extracting data.. Then controller will kick service for database work..
const { userCart } = require('./cart.service');
exports.getCart = (req, res, next) => {
const cart = userCart();
return res.status(200).json(cart);
};
And finally in cart service:
exports.userCart = _ => {
// ... go to database and fetch cart
return [{ prodId: 123, quantity: 2 }];
};
And cart.model.js is responsible for DB schema,
I know the question was too long, but I wanted to explain my question.
I am not saying nestjs should not be used, I am just saying, what about the following structure as it follows the same pattern as angular or nestjs, Right?
With your first point about making the code more readable, why not do something like
#Post('/products')
getAllProducts(#Body() body: any) {}
instead of calling for each part of the body individually, then you can deconstruct the body as you showed with
const {title: title, price: price, description: description} = body;
No need to specify each part of the body that you need as a new parameter, just grab the object itself. The same also goes for #Header(), #Param(), and #Query().
As for how you are setting up your express app, you are completely correct that you can do that; however, if you are working on an open source project, or collaborating with other developers there is nothing that says they have to follow the same format and it could eventually lead to a messy code base. Nest enforces these patterns, similar to how Angular does. Sure, it is still possible to write terrible code, but with an opinionated architecture it does make it more difficult.
NestJS also treats Typescript as a first class citizen, which in my opinion helps get rid of a lot of development problems as well. Plus you get some really cool packages to play with like class-validator and class-transformer to help with validation and transformation of your requests via pipes. You can write an Express server in Typescript, but it isn't necessary, and you can write a NestJS server in JavaScript, but I think you lose a lot of good functionality if you do.
The last point that I don't think has been touched too much it that Nest handles a lot of black boxing for your code through it's modules. If you define a service for a module, it is only available for that module. If you need it in another module you have options, but it helps cut down on the cross-contamination of code and keeps a separations of concerns ideology in mind.
In my opinion, the fact the NestJS gives us specified files for things like authentication (guards), validation and transformation (pipes and interceptors), and error handling (exception filters) makes it easier for anyone to pick up a NestJS server and have a quick understanding of how the request will flow through the server, even if by just looking at the file structure. Personally I know if I see an AuthModule or a guards folder I'm going to be dealing with authentication to some extent.
To answer your final question: there is nothing wrong with how you are showing the express example, especially as you are using Inversion of Control by passing the app into the router to make it work that way, you can absolutely write an Express server that way. Nest just makes you do it that way. (I mean, you could write an entire server using just AppController, AppService and AppModule, but that's really an anti-pattern)
In the end, definitely use what you're comfortable with, but there is a reason Nest has become so popular recently.
it's dirty because you write it in the wrong way
why not use it like this
#Get('/')
getAllProducts(#Body() product: Product) {}
and then destructure it
const {title, price, description} = product
I am having trouble with require executing my code twice. Working on a standard Express app I build Mongoose Schemas, each in it's own files and export them.
//user.js
const User = mongoose.model('User', userSchema)
module.exports = User
//In other files
const User = require('../models/User')
Now I use this in two places in my application and get an error saying that
Cannot overwrite `User` model once compiled.
So the code above is getting called twice as it is the only code right now creating a model. However I would expect Node to only execute it once since it is required in my code.
The really strange part is that checking out an earlier version from Git I get the same error and people working with me on this get the same error. So I have no more ideas where to look for solutions.
Found the solution now.
Turns out I required the module once as models/user and once as model/User which in the cache of require creates two separate modules.
There have been many discussion about this:
one issue
another issue
old PR
It seems that this is due to Windows resolving paths case insensitive while other systems resolve paths case sensitive and node therefore doing it sensitive.
And a new module of'cause gets executed. Simply requiring is both times spelled in lowercase solved the issue.
I think the problem is in "const" that you use to declare the variable "User".
Try to use "var" instead of .
//user.js
var User = mongoose.model('User', userSchema)
module.exports = User
//In other files
var User = require('../models/User')
P/S: This is link that clarify more about "const" and "var":
Const in javascript? When to use it and is it necessary
Hope it helpful for you !
I am writing an application using yeoman angular-fullstack,
I defined some entities that I would like to access from other entities controller.
For example I have in my server->api->Mall I have the following code:
var MallSchema = new Schema({
...
});
module.exports = mongoose.model('Mall', MallSchema);
in other Business controller I would like to search for Mall by _id, using mongoose, But I can not import MallSchema trying to do the following:
mall = mongoose.models("MallSchema").find({_id: "some_mall_id"})
business.mallType = mall.type
business.update();
or nesting Schema's
var MallSchema = new Schema({
business : Business;
});
I really tried in lot of ways, ending up with frustration, googling this yields lots of answers, none have works and few just seems too complicated like this one, I newbie to node.js so I mast been missing somthing simple. any help would be nice for the entire community.
it seems simple but somehow missed from documentation
this seems to work for me now
var business = require('../business/business.model')();
var user = require('../user/user.model')()
Hope it helps.
i'm been trying to display just a simple data from mongolab to nodejs and it displays nothing for some reason.
var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
mongoose.connect("mongodb://db-user:pass#ds049084.mongolab.com:49084/mydb");
mongoose.model('collection',{ name:String });
router.get('/', function(req, res, next) {
mongoose.model('collection').find({},function(err,docs){
res.send(docs);
});
});
I've already saved a name data in the document of the collection in mongolab, the only it shows when i run the debug script
debug=mynode:* npm start is []
does anybody know why is that? thank you.
Fixed it!, man..the problem is the way i named the collections at mongolab. I was missing the "s" at the end of collection. Once i deleted the collection and created another but this time the "s" at the end, then it worked.
e.g.
Naming a collection 'Car' will not work but naming it 'cars' will work somehow
I can't comment yet because of my rep...
But to elaborate.. The reason why you need the "s" at the end is because when you do:
mongoose.model('<the schema you want to map to in your db>',<yourschema>);
"Mongoose automatically looks for the plural version of your model name" in your db.. as it says in the Mongoose documentation.. hence if you type myDbSchema it would look for myDbSchemas (Note the "s") and so thats why in your mongolabs Db the schema would need the extra "s"... confused me for a bit to but I hope this can help someone! :) as this post did help me too.
FYI Mongoose documentation: Mongoose Models Doc
My modules get a mongoose instance injected but now they all use the database that was set on the last mongoose.
For example my main module creates a lot of modules and then calls init on them.
var mongoose = require('mongoose');
//...
mongoose.connect(connString);//specific to finance
var finance = require('finance').init({db:mongoose});
Before I injected the mongoose instance the finance module required mongoose by itself and since it's in the node_modules it gets it's own mongoose. Now; no matter how many main modules I make and how many times I call require it'll always get the instance it got the first time.
Therefor all modules created will be connected to whatever is set by the last connect.
It is possible to use createConnection but still not sure how to inject mongoose, I tried:
var mongoose = require('mongoose');
//...
var c = mongoose.createConnection(connString);//specific to finance
mongoose.connection=c;
var finance = require('finance').init({db:mongoose});
Now I get an error like Cannot overwritefinancemodel once compiled.
Somehow it's very hard to get another instance of mongoose in the same module. This is funny because according to mongoose you should be able to use different connections for different models but since you need a mongoose instance to define a model then how do you inject it? Require keeps returning the same instance over and over again.
Tried the following but both didn't work.
console.log('deleting mongoose cache:',require.cache.mongoose=undefined);
//or this one
console.log('deleting mongoose cache:',delete require.cache.mongoose);
So the question is: how do I inject mongoose in my modules that have models that require a unique database? If main sets up the mongoose instance and connection to inject into the model then how do I prevent it from creating the same one over and over again?
If it's possible to create unique connections with createConnection then what do I inject into the modules? With this connection I can't create models, need a mongoose instance for that. If each model needs to invoke require to get it then mongoose is un injectable.
So mongoose uses a singleton pattern. When you do require("mongoose") you are getting the same instance of a constructor each time as seen at the bottom of mongoose/lib/index.js (source code link here). var mongoose = module.exports = exports = new Mongoose;
To get unique instances, use this pattern:
var singleton = require("mongoose")
var unique = new singleton.constructor();
//now use "unique" just as you would "mongoose"