Mongoosy
Round-trip front-end mongoose.
Install
npm i mongoosy
Setting up the backend
You don't have to npm install express and mongoose. Mongoosy will do that for you.
You import mongoose, express and your app (your server) from mongoosy.
You also send your settings to mongoosy when requiring it. Typically you will want to change the database name (otherwise it defaults to test).
You also need to start the app (the server) on a port of your choice.
// Change these valuesconst dbName = 'mydbname';const serverPort = 3000; const mongoose express app pwencrypt session = // settings for mongoosy connect: url: 'mongodb://localhost/' + dbName ; app;
Mongoosy expect mongoose models to be stored as separate files that each export a monoogse model in a folder called models.
What you require
You get actually require five different things when requiring mongoosy:
- mongoose - the mongoose module - if you should need to use it directly somewhere in your code
- express - the express module - if you should need to use it directly somewhere in your code
- app - the express server created by mongoosy - you can add your own routes, middleware etc to it if needed
- pwencrypt - an encryption function for passwords. Use it to encrypt the passwords if you create any users on the backend.
- session - session middleware function created by the express-session module, use it for things like integrating your sessions with sockets (via a module like express-socket.io-session).
Default settings
You can change which folder to look in for models and a some other settings if you want to. These are the defaults settings used if you don't change them:
query: route: '/api/mongoosy*' expressJson: limit: '1mb' models: path: './models' connect: url: 'mongodb://localhost/test' useNewUrlParser: true useUnifiedTopology: true useCreateIndex: true login: pseudoModel: 'Login' connectedModel: 'User' passwordField: 'password' encryptPassword: true encryptionSalt: 'unique and hard to guess' secureSession: false // set to true if https acl: true result
Setting up the frontend
Note: We expect you to use mongoosy in a frontend environment that support the import command.
Import your models
;const // Replace with names // of models you have defined // in the models folder Cat CatOwner} = mongoosy;
That's it! Now you can use your models exactly as you would on the backend (utilizing the full Mongoose API)!
Note: Make sure to always use them with modern syntax - await/promises - not callbacks.
Example
Just a basic example - you can do so much more since you have all of Mongoose available - population and other advanced queries...
Note: As you can see below we are asking for the property .js in our console.logs. You should only use this in console.logs and for checking properties that might be undefined - it gives the log of objects and arrays a little cleaner look since the objects are proxy objects and otherwise will be logged as such.
{ // Use mongoose from the frontend // through mongoosy // Create a new cat and save to db let aCat = name: 'Garfield' ; await aCat; // after saving the cat it has an id console; // Read all cats from the db let allCats= await Cat; console; // Create a new cat owner and save to db let aCatOwner = name: 'Jon'; await aCatOwner; // after saving the cat owner he has an id console; // Read that cat owner again from the db let foundCatOwner = await CatOwner; console; // Read all cat owners from the db let allCatOwners = await CatOwner; console; }
Gotchas: Reading a property that might be undefined
When you are trying to read a property that might be undefined from a document you will get a Proxy object back. This is because mongoosy is based on Proxy-objects and has now way of knowing if you are asking for a method or a property in the specific case when a property is undefined.
As a workaround you can use document.js.property this will correctly return the property value *even for undefined properties.
Login and ACL
Mongoosy automatically handles logins connected to a model (like User), encrypts passwords, handles sessions... A "fake model" called Login is always available, with the three methods login, logout and check (se example code below).
Mongoosy also allows andvanced ACL (Access Control List) security based on users and/or user roles by giving you two "hooks" you can connect to your own functions in the settings. One prevents queries to run if you return false, the other one lets you filter results. The hooks recieve detailed information about the query and the logged in user - it is up to you to setup your control structure based on this!
There is a working example you can run:
cd node_modules/mongoosy/example
node index
This is the code used in the example:
Backend code (with examples of how to use ACL)
const path = ;const mongoose express app pwencrypt = // settings for mongoosy connect: url: 'mongodb://localhost/login-example-db' acl: query: aclQuery result: aclResult ; app;app;app; { // blacklisting is safest // - i.e.return false unless you want to allow something console; return false || user && userroles || user && userroles && methods0method === 'find' && methodslength === 1 || user && userroles && methods0method === 'save' && methodslength === 1;} { // can modify results console; if !user || !userroles && model === 'Cat' && result instanceof Array console; result = result; return result;} { let User = ; let foundGod = await User; if foundGod return; let god = email: 'god@gmail.com' password: roles: 'god' ; console; await god;} ;
Frontend code (with examples of how to use Login)
;const Cat Login User } = mongoosy; const $ = document; ; { documentbodyinnerHTML = /*html*/` <h1>Mongoosy login/ACL example</h1> <p>First <a href="#">setup/reset the test data</a></p> <p>Then you can try to login as </p> <ul> <li>catwatcher@gmail.com (pw: 1234) - can see cats</li> <li>catcreator@gmail.com (pw: 4321) - can see and create cats</li> <li>god@gmail.com (pw: 666) - can do everything & the only one who can see Garfield</li> </ul> <hr> <a href="#">Add a cat</a> <span class="user"></span> <hr> <h3>Cats</h3> <div class="cats"></div> `; ; ;} { let user = await Login; innerHTML = userjsemail ? `Logged in as <a href="#">Logout</a>` : `<a href="#">Login</a>` await ;} { let email = ; let password = ; let loginResult = await Login; loginResultjserror && ; ;} { await Login; ;} { let name = ; let cat = name ; await cat; if caterror === 'Not allowed by query ACL' ; await ;} { let allCats = await Cat; innerHTML = allCatserror === 'Not allowed by query ACL' ? 'You are not allowed to see the cats.' : allCats;} { // login as a god and create som test data await Login; let catNames = "Garfield" "Heathcliff" "Felix the Cat" "Tom" "Hello Kitty" "Sylvester" "Tigger" "Simba"; let userDetails = email: 'catwatcher@gmail.com' password: '1234' roles: 'catwatcher' email: 'catcreator@gmail.com' password: '4321' roles: 'catwatcher' 'catcreator' ; await Cat; await User; for let name of catNames let cat = name ; await cat; for let detail of userDetails let user = detail; await user; // god leaves the building await Login; ; ;}
Models
User
const Schema model = ;const modelName = 'User'; let schema = email: type: String unique: true required: true password: type: String required: true roles: String; moduleexports = ;
Cat
const Schema model = ;const modelName = 'Cat'; let schema = name: String; moduleexports = ;