Using promisified data access in bogart - javascript

I'm trying to set up a simple blog with bogartjs and couchdb.
I use the viewEngine like this:
var viewEngine = bogart.viewEngine('mustache', path.join(bogart.maindir(), 'views'));
To get the list of all posts from the database I use bogart.promisify to do the actual call and return a promise, like this:
router.get('/postsp', function(req) {
var articles = nano.db.use('articles');
var readlist = bogart.promisify(articles.list);
readlist().then(function(data) {
console.log(data);
return viewEngine.respond('posts.html', data)
});
console.log('render');
});
But this method does not return the template posts.html with the data. This is in the console:
render
{ total_rows: 2,
offset: 0,
rows:
[ { id: '1ec1ba2efd99b08a296022a471000adc',
key: '1ec1ba2efd99b08a296022a471000adc',
value: [Object] },
{ id: '20ce1f108a8bdf2f19f04f42b0001a04',
key: '20ce1f108a8bdf2f19f04f42b0001a04',
value: [Object] } ] }
How do I return/render the template with the outcome of the promise?

The context is required to your object. This is for the same reason:
var log = console.log;
log(15); // exception in browsers.
Pass the context:
var readlist = bogart.promisify(articles.list, articles);

Related

Use the lastest affected data in an object

I have this list object that I return:
return ({
name: data.name,
request: {
method: methodLine[index].method.toUpperCase(),
header: data.request.header,
description: data.request.description,
},
response: [
{
originalRequest: request
}
],
})
And I want to use the data stored in the object request while calling it in the response array in the same return statement. Is there a way to do so?
If you want to do it in the return statement, you can use the comma operator to declare two expressions, the first is a variable declaration to declare request and the second is the returned object using request:
const test = () => {
return (request = 'hello', {
request,
response: [{
originalRequest: request
}]
})
}
console.log(test());
However, this is not so readable and I suggest splitting this into a proper variable declaration before the return statement.
const test = () => {
const request = 'hello';
return {
request,
response: [{
originalRequest: request
}]
}
}
console.log(test());

Mongoose - Populate Array With Reference Property

I have an array of Tags in my Post schema:
tags: [ { type: Schema.Types.ObjectId, ref: 'Tag' } ],
Tag looks like this:
{ name: String }
When I populate the tags array it is of course populated with tag object literals.
Is there a way I can instead have mongoose populate the array with only the name string from the tag?
I have tried only specifying the name, but then name is returned within an object literal.
Currently the population outputs:
[ { name: 'React' }, { name: 'JavaScript' } ]
But I would like it to be:
[ 'React', 'JavaScript']
Is there a way to do this with Mongoose ?
You can make use of 'post' Query Middleware function. This function will be triggered before the actual data is returned by Model.find() or Model.findOne() query. Inside the function you can use Array.map to transform the data to required format.
schema.post('findOne', function(doc) {
// Transform the doc here.
// Example:
// doc.tags = doc.tags.map(tag => tag.name);
});
You could also do the same for handling Model.find().
schema.post('find', function(docs) {
// Transform the doc here.
// Example:
// docs = docs.map(doc => {
// doc.tags = doc.tags.map(tag => tag.name);
// return doc;
// });
});
You can use a virtual that returns a reduction of the tags array:
schema.virtual('plainTags').get(function () {
// first, validate if the 'tags' path is populated
if (!this.populated('tags')) {
return this.tags
}
return this.tags.reduce(function(col, Tag) {
col.push(Tag.name) return col
}, [])
})

Dynamically created attribute on an JS object on the server disappears when sent to the client via jQuery Ajax call on a NodeJS/Express Server

On the client side I request via jQuery Ajax call a certain JS object.
$.get("/foo/requestData",function(data){
console.log("Received data is missing added property: ", data);
});
On the server side I retrieve an array with JS objects after a DB request. I now create on that object a new property and want to send it back to the client:
exports.requestData = function(req, res, next) {
db.myDb.findAll({
where: { bar: true },
order: [
['id']
],
include: [db.table1, db.table2, db.table3, {
model: db.table4
}]
})
.then(function(originalResultObject) {
console.log("This is array with original Objects: ", originalResultObject);
var newResultObject = originalResultObject.map(function(element) {
var valueForNewProperty = "something new";
var newProperty = "newProperty";
element[newProperty] = valueForNewProperty;
return element;
});
console.log("Added property is here: ", newResultObject);
res.locals.thresholdSummary = newResultObject;
res.send(newResultObject);
})
As a result I get on the server:
This is array with original Object:
[Instance {dataValues: {foo: "bar1"}},
Instance {dataValues:{ foo: "bar2"}},
Instance {dataValues: {foo: "bar3"}}, ....]
Added property is here:
[{foo: "bar1", newProperty: "something new"},
{foo: "bar2", newProperty: "something new"},
{foo: "bar3", newProperty: "something new"}, ...]
But on the client site it is missing:
Received data is missing added property:
[{foo: "bar1"},
{foo: "bar2"},
{foo: "bar3"}, ...]
Probably it has something to do with the conversion of JS Object into JSON. The newly added property is ignored after the conversion into JSON while sending to the client. But how do I persistently add a new property on the server and send it to the client?
BTW: is the difference between the array at the very top saying "Instance {dataValues: ...}"?
Just add to the new property has to be added into the dataValues property of the originalObject, i.e.:
originalObject.dataValues.addedProperty = "something new";
You are sending the response before the callback completes. Try this:
exports.requestData = function(req, res, next) {
db.myDb.findAll({
where: { bar: true },
order: [
['id']
],
include: [db.table1, db.table2, db.table3, {
model: db.table4
}]
})
.then(function(originalResultObject) {
console.log("This is original Object: ", originalResultObject);
var newResultObject = originalResultObject.map(function(element) {
var valueForNewProperty = "something new";
var newProperty = "newProperty";
element[newProperty] = valueForNewProperty;
console.log("Added property is here: ", newResultObject);
res.locals.thresholdSummary = newResultObject;
res.send(newResultObject);
return element;
});
})
Note I moved the res.send up into the callback

Return documents matching field array

Using Mongoose with MongoDB, I need to return a series of lookups based on a field of an initial lookup. My Schema is as follows:
var PartSchema = new Schema({
partcode: String,
children: [String]
});
And the data looks like the following:
[{"partcode":"A1","children":["B1","B2","B3","B4"]},
{"partcode":"B1","children":["C11","C21","C31","C41"]},
{"partcode":"B2","children":["C12","C22","C32","C42"]},
{"partcode":"B3","children":["C13","C23","C33","C43"]},
{"partcode":"B4","children":["C14","C24","C34","C44"]}]
I can query for A1's children field by using the following static call:
var childrenOnly =
{children: 1, _id: 0};
PartSchema.static('getChildren', function (partcode, callback) {
return this.find({ partcode: partcode }, childrenOnly, callback);
});
This returns (via express)
[{"children":["B1","B2","B3","B4"]}]
What I need it to return is
[{"partcode":"B1","children":["C11","C21","C31","C41"]},
{"partcode":"B2","children":["C12","C22","C32","C42"]},
{"partcode":"B3","children":["C13","C23","C33","C43"]},
{"partcode":"B4","children":["C14","C24","C34","C44"]}]
I'm guessing an iterative call is required with the first query returning the children array, and then iterating over the children array to get each of the child records.
The general idea is to first try getting the array with the children codes using the findOne() method and then use that array as the query with the $in operator in the find() method to return the full result.
var childrenOnly = {children: 1, _id: 0};
PartSchema.static('getChildren', function (partcode, callback) {
var self = this;
this.findOne({ partcode: partcode }, childrenOnly)
.exec(function (err, doc) {
console.log(doc.children); // {"children":["B1","B2","B3","B4"]}
return self.find({"partcode": {"$in": doc.children} }, callback);
});
});
-- EDIT --
Look into using promises. I haven't tested this yet but I believe it should also do the trick:
var childrenOnly = {children: 1, _id: 0};
PartSchema.static('getChildren', function (partcode, callback) {
var self = this,
promise = this.findOne({ partcode: partcode }, childrenOnly).exec();
promise.then(function (doc) {
return self.find({"partcode": {"$in": doc.children} }, callback);
});
});

How to properly pass data from mongodb using callback when looping through multiple db.Phrase.find calls

I'm receiving params from my get request that looks like this:
{ location: 'Venice', weather: 'Dry', what: 'Yoga', who: 'Bob' }
I then query a mongodb database that loops through each of the key and value pairs and queries for their union in the database.
I then save the returned values to outputCaption and then use a callback to pass the outputCaption back.
The problem is the callback gets called as many times as their key-value pairs looped over.
I'm forced to do this because I need the callback inside the db.Phrase.find call but I call that multiple times...
So I've fixed it using the code in app.get (I wait until all the keys have defined values in outputCaption before doing anything)
It works, but I can't imagine it's the best way to do it so I'm hoping there's a less hackish way?
Thanks
server.js
var express = require('express');
var db = require('./modules/db')
var logic = require('./modules/logic')
...
app.get('/phrase', function(req, res){
logic(req.query, function(outputCaption){
var flag = true
for (key in outputCaption){
if (outputCaption[key] === null){
console.log('Incomplete')
var flag = false;
}
}
if (flag === true) {
console.log(outputCaption);
};
});
})
...
logic.js
var db = require('./db')
var logic = function(params, callback){
var outputCaption = {
who: null,
what: null,
location: null,
weather: null
};
for (key in params){
category = key.toLowerCase();
option = params[key].toLowerCase();
db.Phrase.find({$and: [
{category: category},
{option: option}
]}, function(err, phrases){
if (err) return console.error(err);
var options = Object.keys(phrases).length
var idxOfOptionPicked = Math.floor(Math.random() * options)
outputCaption[phrases[idxOfOptionPicked].category] = phrases[idxOfOptionPicked].phrase
callback(outputCaption)
})
}
}
module.exports = logic;
Instead of firing multiple queries and performing a union of the result at the client side, make use of the query operators to allow MongoDB to do the union for you.
That way you:
Avoid multiple hits to the database.
Avoid multiple callback handlers.
Can post process the results in a single callback handler.
You can modify your code to prepare a query object from the request parameter,
var params = {location: 'Venice', weather: 'Dry', what: 'Yoga', who: 'Bob' };
var query = {};
var conditions = [];
Object.keys(params).forEach(function(key){
var $and = {};
$and["category"] = key.toLowerCase();
$and["option"] = params[key];
conditions.push($and);
});
(conditions.length > 1)?(query["$or"] = conditions):(query = conditions[0]);
Now the constructed query looks like:
{ '$or':
[ { category: 'location', option: 'Venice' },
{ category: 'weather', option: 'Dry' },
{ category: 'what', option: 'Yoga' },
{ category: 'who', option: 'Bob' }
]
}
You can pass this object to the find() method, to get the results in a single hit:
db.Phrase.find(query,callback);
This way your code remains cleaner and easier to understand.

Categories