Moongose schema virtual methods - getter and setters - mongodb

I was working with mongoose in mongodb and encountered virtuals in schema. I was looking for some snippets online for hashing the password and encountered with the following:
why is this._password returned in the get() ?
Actual code:
// virtual field
userSchema
.virtual("password")
.set(function(password) {
this._password = password;
this.salt = uuidv1();
this.hashed_password = this.encryptPassword(password);
})
.get(function() {
return this._password;
});
userSchema.methods = {
authenticate: function(plaintext){
return this.encryptPassword(plaintext) === this.hashed_password;
},
encryptPassword: function(password) {
if (!password) return "";
try {
return crypto // these are crypto methods. Read nodejs crytpo
.createHmac("sha1", this.salt)
.update(password)
.digest("hex");
} catch (err) {
return "";
}
}
};

Related

Mongoose !: statics this undefined

import mongoose, { Schema, Document, Model } from "mongoose";
import { IUser } from "./interface/User.interface";
const userSchema = new Schema<IUserDoc>({
...
});
// Problem
userSchema.statics.findUser = async function (
email: Pick<IUser, "email">
): Promise<IUser | null> {
console.log("this", this); // undefined
try {
// Cannot read properties of undefined (reading 'findOne')
const user = await this.findOne({ email }).exec();
return user;
} catch (err: any) {
return err;
}
};
interface IUserDoc extends IUser, Document {
_id: string;
}
interface IUserModel extends Model<IUserDoc> {
findUser: (email: string) => Promise<IUser>;
}
const User = mongoose.model<IUserDoc, IUserModel>("User", userSchema);
export { User };
// Working
const findUserTest = async (email: string): Promise<IUser | null> => {
try {
const user = await User.findOne({ email }).exec();
return user;
} catch (err: any) {
return err;
}
};
mongoose -v 6.5.1
findUser does not work, but findUserTest works well. I think the problem is with userSchema, but I don't know what the problem is. I'd appreciate it if you could give me a hint.

ES6 promise will not work always with mongodb replication set

I did follow How to use MongoDB with promises in Node.js?. The answer 4 by(https://stackoverflow.com/users/5371505/pirateapp), works well with regular mongodb server. But it will not work always with a mongoDB replication set.
const mongodb = require('mongodb');
const MongoClient = mongodb.MongoClient;
// the url talking to replicaSet does not work, while the url with regular mongoDB sever seems working for me.
// const url = 'mongodb://alexlai:alex1765#arch16GMongo01.yushei.me:27017,arch16GMongo02.yushei.me:27017,arch16GMongo03:27017/YuShei?replicaSet=odroid00&connectTimeoutMS=300000';
url = 'mongodb://172.16.1.108/YuShei';
let db = {
open : open,
}
function open(){
return new Promise((resolve, reject)=>{
MongoClient.connect(url, (err, db) => {
if (err) {
reject(err);
} else {
resolve(db);
}
});
});
}
function close(db){
if(db){
db.close();
}
}
// module.exports = db;
// const db = require('./mongoDBServer.js');
const assert = require('assert');
const collectionName= 'yuTsaiLpr20161021'; // a collection contains 500 docs.
// this will hold the final array taht will be sent to browser
// a global variable will be declared with upper camel
let Array = [];
// this will hold database object for latter use
let Database = '';
// global query string and projection
let Query = {};
let Projection = {};
let Collection ={};
let checkoutCarPromise = new Promise((resolve, reject)=>{
Database = null;
db.open() // no ';' semi-column this is a promise, when successful open will be reolved and return with db object, or reject
.then((db)=>{
Database = db; // save it globally
return db.collection(collectionName);
})
.then((collection)=>{
if(collection == 'undefined') reject('collection not found!!');
Collection = collection; //seave it globally
return(collection);
})
.then((collection)=>{
return collection.find(); // return a cursor
})
.then((cursor)=>{
return cursor.toArray();
})
.then((array)=>{
console.log('array[499]: ', array[499]);
Array.push(array[499]);
})
.then(()=>{ // reread to find this car
return Collection.find({plateText:{$regex: /8920/}});
})
.then((cursor)=>{
return cursor.toArray();
})
.then((array)=>{
Array.push(array);
resolve(Array);
})
})
.catch((err)=>{
return(err);
console.error('the checkoutCarPromiserror is: ', err);
})
Promise.all([checkoutCarPromise]).then(results => {
console.log('checkoutCarPromise last resolve value: ', results[0]);
console.log('Array: ', Array);
Database.close();
})
// this will get you more infos about unhandled process
process.on("unhandledRejection", (reason) => {
console.log(reason)
})

How to stop inserting duplicate records before saving in db?

I'm trying to save students records, but it should not take duplicate records. How is it possible? In below code i have tried to do
app.post("/save",function(req,res){
var std=new student(req.body);
student.findOne({},function(err,success){
if(err)
{
console.log(err);
}
else
{
// console.log(success);
std.save(function(err,success){
if(err)
{
console.log(err);
}
else
{
console.log("inserted");
console.log(success);
}
});
}
})
});
Here is the sample code. Please note that the existence of the value in MongoDB database depends on the req.body as mentioned in the OP.
In the below code, I have only name attribute in the Student collection. So, the duplicate check is based on the name attribute only.
You may need to change the code if you would like to check for the specific attribute in the collection to determine the duplicate value.
Please note that my Student collection has only attribute in the schema as well.
var express = require('express');
var MongoClient = require('mongodb').MongoClient;
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
var Student = mongoose.model('Student', { name: String });
var app = express();
var bodyParser = require('body-parser');
var app = express();
var urlencoded_body_parser = bodyParser.urlencoded({
extended: true
});
app.use(bodyParser.json());
app.use(urlencoded_body_parser);
app.post("/save", function (req, res) {
console.log(req.body);
var student = new Student(req.body);
Student.findOne(req.body, function (err, success) {
if (err) {
console.log(err);
res.send(err);
}
else {
console.log(success);
if (success == null) {
student.save(function (err, success) {
if (err) {
console.log(err);
res.send(err);
}
else {
console.log("inserted");
console.log(success);
res.send("success");
}
});
} else {
res.send("Student already present");
}
}
})
});
app.listen(3000);
Output:-
First time execution:-
Input:-
{
"name" : "john"
}
Output:-
success
Subsequent executions with the same input json:-
Output:-
Student already present

Using design documents in pouchDB with crypto-pouch

After testing pouchDB for my Ionic project, I tried to encrypt my data with crypto-pouch. But I have a problem with using design documents. I used the following code:
One of my design documents:
var allTypeOne = {
_id: '_design/all_TypeOne',
views: {
'alle_TypeOne': {
map: function (doc) {
if (doc.type === 'type_one') {
emit(doc._id);
}
}.toString()
}
}
};
For init my database:
function initDB() {
_db = new PouchDB('myDatabase', {adapter: 'websql'});
if (!_db.adapter) {
_db = new PouchDB('myDatabase');
}
return _db.crypto(password)
.then(function(){
return _db;
});
// add a design document
_db.put(allTypeOne).then(function (info) {
}).catch(function (err) {
}
}
To get all documents of type_one:
function getAllData {
if (!_data) {
return $q.when(_db.query('all_TypeOne', { include_docs: true}))
.then(function(docs) {
_data = docs.rows.map(function(row) {
return row.doc;
});
_db.changes({ live: true, since: 'now', include_docs: true})
.on('change', onDatabaseChange);
return _data;
});
} else {
return $q.when(_data);
}
}
This code works without using crypto-pouch well, but if I insert the _db.crypto(...) no data is shown in my list. Can anyone help me? Thanks in advance!
I'm guessing that your put is happening before the call to crypto has finished. Remember, javascript is asynchronous. So wait for the crypto call to finish before putting your design doc. And then use a callback to access your database after it's all finished. Something like the following:
function initDB(options) {
_db = new PouchDB('myDatabase', {adapter: 'websql'});
if (!_db.adapter) {
_db = new PouchDB('myDatabase');
}
_db.crypto(password)
.then(function(){
// add a design document
_db.put(allTypeOne).then(function (info) {
options.success(_db);
})
.catch(function (err) { console.error(err); options.error(err)})
.catch(function (err) { console.error(err); options.error(err);})
}
}
initDB({
success:function(db){
db.query....
}
)

Why won't my Mongoose model load?

This is my locationsModel.js file:
var LocationSchema, LocationsSchema, ObjectId, Schema, mongoose;
mongoose = require('mongoose');
Schema = mongoose.Schema;
ObjectId = Schema.ObjectId;
LocationSchema = {
latitude: String,
longitude: String,
locationText: String
};
LocationsSchema = new Schema(LocationSchema);
LocationsSchema.method({
getLocation: function(callback) {
return console.log('hi');
}
});
exports.Locations = mongoose.model('Locations', LocationsSchema, 'locations');
In my controller, I have:
var Locations, mongoose;
mongoose = require('mongoose');
Locations = require('../models/locationsModel').Locations;
exports.search = function(req, res) {
var itemText, locationText;
Locations.getLocation('info', function(err, callback) {
return console.log('calleback');
});
return;
};
When I run it, I get the following error:
TypeError: Object function model() {
Model.apply(this, arguments);
} has no method 'getLocation'
What am I missing?
I think what you're after is statics rather than a method.
As per the docs:
I think you should define the getLocations function as follows (looking at your use of getLocations you've got a string parameter as well as the callback:
LocationsSchema.statics.getLocation = function(param, callback) {
return console.log('hi');
}
EDIT:
The difference between statics and methods is whether you are calling it on the "type" or "objects" of that type. Adapted from the examples:
BlogPostSchema.methods.findCreator = function (callback) {
return this.db.model('Person').findById(this.creator, callback);
}
which you'd invoke as such:
BlogPost.findById(myId, function (err, post) {
if (!err) {
post.findCreator(function(err, person) {
// do something with the creator
}
}
});