Get missing fields on mongoose scheme - node.js

I need to get a count of all the missing or empty fields in mongoose schema
The idea is to have a list of all the properties in a mongoose schema that are blank or does not have a value, so I can make a function to know what percentage of the document is missing.
I tried with count and count by null, but i don't know the query to get the results.

You can have a function like this in your application code:
const getDocumentCompleteness = (doc) => {
const totaFieldCount = Object.keys(doc).length;
let completedFieldCount = 0;
for(let key in doc) {
if(doc[key] !== undefined && doc[key] !== null && doc[key] !== '') {
completedFieldCount += 1;
}
}
return [totaFieldCount, completedFieldCount];
}
Whenever you need to get the completeness of a document, you can do this:
const [totaFieldCount, completedFieldCount] = getDocumentCompleteness(document);
// where document is the object representing the document you got from the database
I hope that helps.

Related

Error in returning new value from Mongoose Database (Nodejs)

When I execute a find query in mongodb after executing a findOneAndUpdate query the data that is returned is not the updated one eventhough the data has been correctly updated in the database.
I find the list of all entries which have a particular code/codes,
let codeList:Array<CodeBase> = await codebaseModel.find({codeBaseId: codes});
I loop through each entry and where the fileTree needs to be updated, I get the directory tree and update it
if (codeList.length > 0) {
codeList.forEach( (e): void => {
if (e.fileTree === 'To be updated') {
let tree = directoryTree(src/uploads/${e.codeBaseId}/unzipped/);
let treeData = JSON.stringify(tree);
let value = codebaseModel.findOneAndUpdate(
{ codeBaseId: e.codeBaseId },
{ fileTree: treeData },
{ upsert:true,new:true, }
);
}
});
}
I need get the updated list again (so as to ensure that I have the entries with the updated fileTree values.
let codeListNext:Array<CodeBase> | null | void = [];
await codebaseModel.find({
codeBaseId: codes,
},).then((value:Array<CodeBase>)=>{
codeListNext = value;
});
console.log(Firstlist length is ${codeListNext});
However, the list that is returned is the old list. However, the mongodb database has updated values. I tried using async await but was not successful. Can someone help me understand where am I going wrong ?

CoreMongooseArray to Normal Array

I'm shortlisting the 2 elements from one schema and want to update in another schema. for that i used slice method to shortlist first 2 elements from an array. but am Getting
CoreMongooseArray ['element1','element2']
instead of ["element1", "element2"]
How do i remove "CoreMongooseArray" ?
connection.connectedusers.find({}, async (err, docs) => {
if(err) throw err;
var users = docs[0].connectArray;
if (docs[0] != null && users.length >= 2) {
var shortListed = users.slice(0, 2);
try {
await connection.chatschema.updateMany({}, { $push: { usersConnected: [shortListed] } }, { upsert: true });
} catch (err) {
res.status(201).json(err);
}
}
You need to add lean() to your query.
From the docs:
Documents returned from queries with the lean option enabled are plain javascript objects, not Mongoose Documents. They have no save method, getters/setters, virtuals, or other Mongoose features.
If you already got the mongoose array and like to convert to simple js array
const jsArray = mongooseArray.toObject();
https://mongoosejs.com/docs/api/array.html#mongoosearray_MongooseArray-toObject
For some reason .toObject() didn't work for me. lean() option works, but it's not suitable when you already have an object with mongoose array in it. So in case if you already have mongoose array and you want just to convert it to plain js array you can use following code:
function mongooseArrayToArray(mongooseArray) {
const array = [];
for (let i = 0; i < mongooseArray.length; i += 1) {
array.push(mongooseArray[0]);
}
return array;
};
usage:
const array = mongooseArrayToArray(mongooseArray);
If you just want to convert the CoreMongooseArray to a normal array without changing anything else:
const jsArray = [...mongooseArray];

Cloud Functions & Firestore: Iterate over document.data

The database structure looks like this:
User {id}
Settings (Collection)
device_uids(document)
{device_uid_1}: Boolean
(...)
{device_uid_n}: Boolean
I want to get the document and access all of the device_uids within that document.
I tried like this, however the console logs, that forEach is not definded:
const settings_ref = admin.firestore().collection('User').doc(uid).collection('Settings').doc('device_uids');
settings_ref.get()
.then(snap =>{
let uids = snap.data();
uids.array.forEach(element => {
let device = element.key;
if(device != device_uid){
//GO ON
}
});
})
How can I access the values individually?
You don't have a field called array in your document, so uids.array will always be undefined. If you just want to iterate all the properties of the document, it's just like iterating all the properties of a plain old JavaScript object:
const data = snap.data();
for (const key in data) {
const value = data[key];
// now key and value are the property name and value
}

Mongoose dynamic query

Query parsed from URL, example :
?year=2014&cat=sonny
Or it can be
?year=2014&id=223&something=high&cat=sonny
I could do
Model.find({year: 2014}).where('cat').equals('sonny')
But what if there a second example? How can I make it dynamic?
You can set the query to a variable and add multiple conditions:
var query = Model.find();
query.where('year').equals('2014');
query.where('cat').equals('sonny');
query.where('id').equals('223');
query.where('something').equals('high');
query.exec(callback);
For dynamic, just pass the query to a for loop and iterate through an array of your filter objects:
var query = Model.find();
var filters = [
{fieldName: "year", value: "2014"},
{fieldName: "cat", value: "sonny"}
...
];
for (var i = 0; i < filters.length; i++) {
query.where(filters[i].fieldName).equals(filters[i].value)
}
query.exec(callback);
Building on the cdbajorin's answer - I suspect many coders are trying to take input from a form and dynamically build a Mongoose filter from the end users input. (or at least that was my scenario).
If you 'name' the html input fields the same as your Mongoose Schema name
<input type='text' name='person.address'>
Then in your code you can use the req.body object
var query = Model.find();
for (var fieldName in req.body)
{
if(req.body.hasOwnProperty(fieldName)) //no inherited properties
{
if(req.body[fieldName]) //get rid of empty fields
{
query.where(fieldName).equals(req.body[fieldName]);
}
}
}
query.exec(function(err,data){console.log('QUERY EXECUTE : ' + err, data, data.length);});

Apply function to field on all documents returned from MongoDB query in nodejs

I want to apply a truncate(string, words) function to the 'body' field of all Article documents returned by a mongoose query. An example would be as follows:
Article.find({})
.sort({'meta.created': 'desc'})
.limit(6)
.exec(function(err, articles) {
// Truncate the article.body field on each articles here?
res.render(articles: articles});
});
With a simple truncate function something like:
function truncate(string, words) {
var value_arr = string.split( ' ' );
if( words < value_arr.length ) {
value = value_arr.slice(0, words).join( ' ' );
}
return value;
}
How can I apply this function to each articles body field (retaining the articles structure for use in a template)? Thanks in advance.
The proper way, I believe, would be to add a truncatedBody property to your Article, and implement the truncate method as a static:
Article.methods.setTruncatedBody = function(limit){
//If truncatedBody is already computed, don't do anything
if(this.truncatedBody)
return;
var value_arr = body.split( ' ' );
if( limit < value_arr.length ) {
this.truncatedBody = value_arr.slice(0, words).join( ' ' );
}
else
this.truncatedBody = body;
}
Then, in your controller:
Article.find({})
.sort({'meta.created': 'desc'})
.limit(6)
.exec(function(err, articles) {
for(var article in articles)
article.setTruncatedBody(5);
res.render(articles: articles});
});

Resources