Postprocess Sequelize finders with Express - node.js

I am new to Javascript.
I am developping an API to retrieve information from MySQL with :
Node.js
Express
Sequelize
I developed the following controller based on a Sequelize finder (findByPk, to retrieve information by a primary key). There are several nested includes.
exports.findByPk = (req, res) => {
Poi.findByPk(req.params.id,{
attributes: [
'name',
'description'
],
include: [{
model: Source,
attributes: ['originalId'],
where: {source: 'google'}
},{
...
}]
})
.then(data => {
res.send(data);
})
};
As far as I understand, the finder outputs a relatively complex Sequelize instance object data which is passed in res.send (but the API gives access to a proper Json).
I need to postprocess data before passing the result in res.send :
I need to retreive information from a Google API using the data fields, and add this information to the API output
I need to compute some values based on the data fields, and add these values to the API output (long story short, it cannot be part of the Sequelize query because of a known issue in Sequelize)
How to retrieve the values I need from data ? Should I treat it as a regular javascript object, understand its structure, and manually retrieve the values I need ? Or are there methods for that ?
After that, how to add information to data ? Should I actually add information to data, or create a new object ? Should it be a Sequelize object or can it be a regular json-like javascript object ?
Thank you very much

You can just turn data (that is actually an instance of the Poi Sequelize model) into a plain JS object and afterwards work with it in a regular way:
.then(data => {
const plainObject = data.get({ plain: true });
plainObject.newProp = 1
// some work here including accessing Google API
...
res.json(plainObject);

Related

Is there a way to filter through data based on if a search query is present in the string in mongodb?

I have data that looks like this in my mongoDB atlas database:
object: {
keywords: ['Homelessness', 'Food', 'Poverty']
}
I'm creating a filtering component for my MERN stack website and wanted to add a search feature for keywords like these that are present in each object in the database. If a search query was Homelessness for example, then the object above would show up since it has Homelessness as one of its keywords. But say for example I enter Homeless as a search query, the ones with Homelessness won't pop up because Homeless =/= Homelessness. Is there a way to somehow find if the search query is within a string inside an array which is all inside a json object?
Here is what I tried so far which gets the result I described in the situation above:
const getFilteredProjects = async (req, res) => {
// Initializing request object that will be sent to retrieve DB information
var request = {}
if (req.query.keywords !== '') {
request["keywords"] = req.query.keywords
}
console.log(request)
const projects = await Project.find(request).sort({ assignment_type: 1 })
res.status(200).json(projects)
}
How can I somehow access each string inside the keywords array and see if the search query is present in it? Is that possible with mongodb or would I have to somehow do it through javascript? If that's the case I'm not sure how I could do that, I would appreciate it if I could get some help.

Express, Mongoose, db.findOne always returns same document

I am attempting a CRUD app with MEAN stack. I am using mongoose in Express to call to the MongoDB. I am using the FindOne function with a specified parameter, and it's always returning the same (incorrect) document.
I know I am connected to the correct database, since I get a document back from that collection, but it's always the same document, no matter what I pass as the parameter.
module.exports = mongoose.model('Player', playersSchema, 'players'); //in player.js
const Player = require('./model/players');
app.get('/api/player/:id', (req, res) =>{
Player.findOne({id: req.params.playerId},
function(err, player) {
if(err) {
res.json(err);
}
else {
res.json(player);
}
});
});
I have 3 separate "players", with three distinct "playerID" fields (38187361, 35167321, 95821442). I can use Postman to GET the following URL, for example:
http://localhost:3000/api/player/anythingyouWantInHere
and it will return 38187361, the first document. I've been over this website, many tutorials, and the Mongoose documentation and I can't see what I'm doing wrong..
I'd like to eventually find by playerId OR username OR email, but one hurdle at a time...
From the mongoose documentation of findOne, if you pass Id a null or an empty value, it will query db.players.findOne({}) internally which will return first document of the collection everytime you fetch. So make sure you are passing non-empty id here.
Note: conditions is optional, and if conditions is null or undefined,
mongoose will send an empty findOne command to MongoDB, which will
return an arbitrary document. If you're querying by _id, use
findById() instead.
Your route is '/api/player/:id', so the key on the req.params object will be 'id' not 'playerId'.
I don't know what/where/if you're populating the playerId param, but if you update your query to call req.params.id it should actually change the document based on the path as you seem to be wanting to do.
I had the same problem, and it was that the name of column's table was different from the model I had created.
In my model the name of the wrong column was "role" and in my table it was "rol".

Google Datastore not retrieving entities

I have been working with the google cloud library, and I can successfully save data in DataStore, specifically from my particle electron device (Used their tutorial here https://docs.particle.io/tutorials/integrations/google-cloud-platform/)
The problem I am now having is retrieving the data again.
I am using this code, but it is not returning anything
function getData(){
var data = [];
const query = datastore.createQuery('ParticleEvent').order('created');
datastore.runQuery(query).then(results => {
const event = results[0];
console.log(results);
event.forEach(data => data.push(data.data));
});
console.log(data)
}
But each time it is returning empty specifically returning this :
[ [], { moreResults: 'NO_MORE_RESULTS', endCursor: 'CgA=' } ]
, and I can't figure out why because I have multiple entities saved in this Datastore.
Thanks
In the tutorial.js from the repo mentioned in the tutorial I see the ParticleEvent entities are created using this data:
var obj = {
gc_pub_sub_id: message.id,
device_id: message.attributes.device_id,
event: message.attributes.event,
data: message.data,
published_at: message.attributes.published_at
}
This means the entities don't have a created property. I suspect that ordering the query by such property name is the reason for which the query doesn't return results. From Datastore Queries (emphasis mine):
The results include all entities that have at least one value for
every property named in the filters and sort orders, and whose
property values meet all the specified filter criteria.
I'd try ordering the query by published_at instead, that appears to be the property with a meaning closest to created.

How to use groupBy in Bookshelf js?

how to use groupBy in Bookshelf JS, here is my Controller code.
router.route('/fetchStudentAttendance')
.post(function(req, res) {
StudentAttendance
.query(function (qb){
qb.where('date', '>=', req.body.date);
qb.groupBy("students_id");
})
.where({'class_id': req.body.class_id, 'section_id': req.body.section_id})
.fetchAll({ withRelated: [{'StudentRef':function(qb) {qb.column('id', 'first_name', 'middle_name', 'last_name')}}]})
.then(studentAttendance => {
let content = {
data: studentAttendance,
success: true,
message: 'Record Not Found',
};
return res.send(content);
})
.catch(error => {
let content = {
data: error,
success: false,
message: 'Error while fetching Student Attendance.',
};
return res.send(content);
});
});
when i am trying to "groupBy" employee_id it will give Error like this.
code:"42703"
file:"parse_relation.c"
length:110
line:"3194"
name:"error"
position:"127"
routine:"check_ungrouped_columns_walker"
severity:"ERROR"
TL;DR
Use Bookshelf's built-in Collection manipulation to do custom groupBy after the .fetchAll()
OR
Use raw Knex to generate your query and results as needed, since groupBy will require some SQL aggregation definitions. This can be a Knex query result, or a Bookshelf object.
More Words
Bookshelf isn't exactly a query generator; not like the query libray KnexJS it is built off of. Bookshelf is made as a way to collect rows from your DB as Object Models. A SQL "groupBy" clause is kind of custom to the query, and Bookshelf itself implements lodash methods, like lodash's groupBy as stated in their docs. However, that is a server-side grouping on the queried data, it is not using SQL to do so.
When using your Model in Bookshelf, you should use new Model or Model.forge() before you fetch (or in case of many, .fetchAll()). You can start a Knex query, in a way, by using Model.query (see docs), but be aware that is returning Bookshelf objects. I typically use .query(function (qb) {}) to do some custom knex, like a custom WHERE clause or an qb.orderBy('prop'). Since groupBy would include 'many', you would want Model.query().fetchAll(), and be aware of custom aggregation in that query (Bookshelf will likely handle it, but it wouldn't be exactly like the model you defined, especially with custom methods). Using Knex directly might be a good option too.

Leveraging both GraphQL and Mongoose

Is it possible to leverage both GraphQL and Mongoose?
So far, I have been able to integrate both GraphQL and Mongoose to handle populating the database, but I am struggling to understand how this can work to retrieve data, specifically data with nested references.
Consider this schema:
const fooSchema = new Schema({
name: { type: 'String', required: true },
bar: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Bar',
required: false,
}],
});
The Bar schema is essentially the same, with just a field for "name".
Is it possible to run a GraphQL query to populate the data with the references in 'bar'?
Currently, we are using GraphQL-Tools to create our typeDefs, Mutations, and Queries which looks something like this:
const typeDefs = `
type Foo {
name: String!,
bars:[Bar]
}
type Bar {
_id: ID,
name: String,
}
type Query {
allFoos: [Foo!]!
foo(_id: ID!): Foo
}
type Mutation {
...
}
`;
module.exports = makeExecutableSchema({typeDefs, resolvers});
And finally a query directive that looks like this:
const allFoos = async (root, data) => {
return await Foo.find({});
};
I am able to change the query directive to use .populate() to get Bar, but that does not actually end up populating the results, which I think is because of the way the typeDefs are set up.
So is it possible to make these two concepts work together? Does it even make sense to use them both?
As they describe GraphQL:
GraphQL is a query language for your API, and a server-side runtime
for executing queries by using a type system you define for your data.
GraphQL isn't tied to any specific database or storage engine and is
instead backed by your existing code and data.
Where as mongoose is
Writing MongoDB validation, casting and business logic boilerplate is
a drag. That's why we wrote Mongoose
Monogoose work with mongodb validation whereas graphql is a query language for the API.
You can read a basic example from here about Setting up a simple GraphQL Server with Node, Express and Mongoose.
These two are completely different. Mongoose work when you are performing any operation on database, whereas grapgl comes in picture when you call a API. Graphql validate your API input parameter and return parameter. If you are adding these two in single app. It will work well.
Mongoose will validate your db operation.
GraphQL will validate your API input and output parameter.

Resources