Mask data in Mongoose find operation - node.js

The requirement is to mask mobile number and show only last 4 digits. I do not want this to be performed at client instead mask it before sending the response. I am not sure how to modify transaction object to mask the data. I want to check if there is any mongoose function to do this. If not please suggest me the best way to mask a selected field.
Logic to fetch transactions
Transaction.find(query).populate('from','name mobile email').sort({ createdAt : -1 }).skip((page) * limit).limit(limit).exec((err, transaction) =>{
if(transaction){
Transaction.countDocuments({to:id,paymentStatus:"SUCCESS"},function(err,count){
return res.status(200).send({transaction,count:count});
});
}
else if(transaction==null) return res.status(200).send("No Transactions Found");
else if(err) return res.status(400).send("Error Occurred");
});
User.Model.ts - Merchant model is similar with some additional fields
var User= new mongoose.Schema({
email:{type:String,required:"E-Mail address cannot be empty",unique:true},
mobile:{type:String,required:"Mobile number cannot be empty",min : [10,"Please provide a valid 10 digit mobile number"],unique:true},
password:{type:String,required:"Password cannot be empty",minlength : [4,"Password must be more than 4 characters"]},
.......some unrelated fields...
});
Transaction.Model.ts
var transactionSchema = new mongoose.Schema({
from:{ type: mongoose.Schema.Types.ObjectId, required: true, ref: 'User' },
amount : {type:String,required:true},
to:{ type: mongoose.Schema.Types.ObjectId, required: true, ref: 'Merchant' },
paymentStatus:{type : String, default : "INCOMPLETE"},
.......some unrelated fields...
});
Current output
{"transaction":[{"paymentStatus":"SUCCESS","isDisputed":true,"_id":"5eb8e50b3e2adb3b74e85d4f","from":{"_id":"5eb8e50a3e2adb3b74e85d43","name":"John Doe","email":"test#gmail.com","mobile":"9999999999"},"amount":"40","to":"5eb8e50a3e2adb3b74e85d46"}],"count":1}
Expected output
{"transaction":[{"paymentStatus":"SUCCESS","isDisputed":true,"_id":"5eb8e50b3e2adb3b74e85d4f","from":{"_id":"5eb8e50a3e2adb3b74e85d43","name":"John Doe","email":"test#gmail.com","mobile":"*******999"},"amount":"40","to":"5eb8e50a3e2adb3b74e85d46"}],"count":1}

You can use string-masking to mask the fields after you fetch them.
Mongoose plugin, virtuals or getters would also involve you to iterate over the array so the end result is same.
let stringMasking = require('string-masking');
...
transactions = transactions.map(transaction => {
let mask = stringMasking(transaction.from.phone, 0);
transaction.from.phone = mask.response;
return transaction;
});
...
return res.status(200).send({transaction,count:transaction.length});
Also its better to make the password not included in all find queries if not needed. Can be done by :
password: {type: String,select: false}

Related

Mongoose: Sort Documents based on array properties

Good morning/afternoon.
I'm trying to sort out documents based on multiple array properties to make a "Ranking" system.
The user Schema that i want to sort:
const UserSchema = new mongoose.Schema(
{
// ... Rest of the code
modules: {
party: Array,
bank: Array,
// ... Rest of the code
},
{ strict: false }
)
Which every new 'partner' added to the user, pushes This to the modules.bank (or party):
{
_id: "some_randomgenerated_id",
id: "id of the monster on the database",
level: Number,
exp: Number,
stats: {
attack: Number
defense: Number,
additional: {
attack: Number,
defense: Number
}
}
I want to sort the Users based on each partner's streght combined, like partner[0].stats.attack + .defense + (additional stats) and so on...
I Tried using aggregate, but haven't got too far with it.

how to query mongoDb with array of boolean fields?

My mongoose model schema looks like -
{
email: { type: String},
Date: {type: Date},
isOnboarded: {type: Boolean},
isVip: {type: Boolean},
isAdult: {type: Boolean}
}
In my frontend I have 3 checkboxes for "isVip", "isOnboarded" and "isAdult" options. If they are checked I'm adding them to an array, which I'll pass to the server. Let's say if "isVip" and "isAdult" are checked, I will pass [isVip, isAdult] in post api to server. Now how can I write a query to get all the documents with the fields in array as true i.e in above example how can I retrieve all docs with {isVip: true, isAdult:true}
I'm having trouble because the array values keep changing, it can be only one field or 3 fields. I couldn't find a way to give condition inside mongoose query.
User.find(
{ [req.query.array]: true},
{ projection: { _id: 0 } }
)
User is my mongoose model.
I want something like this (documents with the value 'true' for the fields given in the array) and 'req.query.array' is the array with field names I passed from frontend.
You have to create your object in JS and pass then to mongo in this way:
var query = {}
if(isVip) query["isVip"] = true;
if(isOnboarded) query["isOnboarded"] = true;
if(isAdult) query["isAdult"] = true;
And then you can use the mongoose method you want, for example:
var found = await model.find(query)
And this will return the document that matches the elements.
Also, note that this is to create and object to be read by the query, so you can use this into an aggregation pipeline or whatever you vant
Check the output:
var query = {}
query["isVip"] = true;
query["isOnboarded"] = true;
query["isAdult"] = true;
console.log(query)
Is the same object that is used to do the query here
{
"isVip": true,
"isOnboarded": true,
"isAdult": true
}
Also, to know if your post contains "isVip", "isOnboarded" or "isAdult" is a javascript question, not a mongo one, but you can use something like this (I assume you pass a string array):
var apiArray = ["isVip","isAdult"]
var isVip = apiArray.includes("isVip")
var isAdult = apiArray.includes("isAdult")
var isOnboarded = apiArray.includes("isOnboarded")
console.log("isVip: "+isVip)
console.log("isAdult: "+isAdult)
console.log("isOnboarded: "+isOnboarded)

save Embed docs as an object using mongoose?

I have a schema like this
const user = new Schema({
firstName: { type: String, required: true },
lastName: { type: String , required: true},
phone:{type: Number, unique true}
embeddedDocsAsJson: {} // not as an array
},
{ minimize: false }
)
I want to use embeddedDocsAsJson because of two reasons
In case of array a duplicate data can be pushed to array , if I use json it will not occur as I'll use unique id as json key
Retrieval will be faster as I don't have to iterate on the array . I can fetch it from the json key
Problem:
Firstly I'm inserting firstName and lastName phone.
And embeddedDocsAsJson is added while updating the docs below is my code for updating
let user = await User.findOne({phone: somenumber})
user.embeddedDocsAsJson.someId = someObject // getting error in this line because `user.embeddedDocsAsJson` is `undefined`
user.save()
I'm adding value to embeddedDocsAsJson while updating
EmbeddedDocs are by-default array if you want to save object in your collection below code will work.
let user = await User.findOne({phone: somenumber})
user.embeddedDocsAsJson = {}
user.embeddedDocsAsJson.someId = someObject // getting error in this line because `user.embeddedDocsAsJson` is `undefined`
user.save()

String + autoincrement number on mongoose

I want to create a String + number every time a value is inserted on database (the number must be autoincrement).
Is it possible to do in Schema? Or do I need to do that before the value's inserted on database?
'question' -> String followed by an autoincrement number
var random = [{
question: 'question1'
},{
question: 'question2'
},{
question: 'question3'
},{
question: 'question4'
}];
const RandomSchema = new Schema({
question: {
type: String,
unique: true
}
})
Autoincrement fields in Mongodb, don't work exactly the same way that they do in an RDBMS. There is a lot more overhead involved. Never the less, creating an auto field is a solved problem. There is also a third party mongoose-autoincrement package that make it a lot easier.
Extending, from that. Your problem is a solved problem too. Because
the string part will always be the same
Simply use string concatenation to prepend 'question' to the auto increment field at display time.
Here is what I implemented with one of the approaches #e4c5 pointed out, without the use of a third-party package.
Define add.js as below:
db.counters.insert(
{
_id: "itemid",
seq: 0
}
)
function getNextSequence(id) {
var ret = db.counters.findAndModify(
{
query: { _id: id },
update: { $inc: { seq: 1 } },
new: true
}
);
return ret.seq;
}
db.randoms.insert(
{
question: "question"+getNextSequence("itemid"),
}
)
db.randoms.insert(
{
question: "question"+getNextSequence("itemid"),
}
)
After starting a mongod instance, do mongo < add.js.

Node-Orm hasOne relationship is not formed correctly

var User = db.define('user', {
user_id : Number,
work_phone : String,
mobile_phone : String
}, {
id: 'user_id'
, autoFetch: true
, cache: true
}) ;
var UserCloud = db.define('user_cloud', {
id : Number,
file_path : String,
user_id : Number,
file_size : String, //not used
date_added : Date,
date_modified : Date,
is_disclaimer : Number,
folder_id : String
}, {
autoFetch: true
}) ;
UserCloud.hasOne('user', User, {
field: 'user_id'
, autoFetch: true
})
This relationship doesn't form! It sets up the functions getUser and hasUser on the UserCloud instances, but it doesn't set the user property.
However setting a simlar hasOne relationship up on user works for other "Classes". Further the UserCloud has other relationships that are unformed as well.
I don't know what other examples to give, nor do I know where to look. I didn't see anything in One.js that provided direction, I am really in the dark here and looking for any pointers / insight.
OK this wasn't posted win the original question:
var UserCloud = db.models.user_cloud
var UserCloudFolder = db.models.user_cloud.user_cloud_folders
THe big issue is that there was an accidental chaining of models on the second model:
var UserCloudFolder = db.models.user_cloud.user_cloud_folders\
SHould be
var UserCloudFolder = db.models.user_cloud_folders
Which fixed it. I discovered that orm was trying to link the UserCloud back to another UserCloud which lead me to look beyond the definition of the association. SO there you have it - no errors, just not working.

Resources