Serching by role mongoose - node.js

I am trying to retrieve users based on role but with every role queried, I want to also retrieve admin too. I am not sure how to go about it. This is how I currently retrieve based on role
public async listAllStaffs(query: ListStaffsRequestQueryDTO) {
var conditions = { }
if (query.role) {
conditions = { role: query.role, 'hub.id': query.merchant };
} else {
conditions = {'hub.id': query.merchant };
}
const data = { page: query.page, limit: query.limit, conditions: conditions};
const all = await this.list(data);
const pagination = {
page: all.page,
limit: all.limit,
rowCount: all.rowCount,
pageCount: all.pageCount
};
const staffs = all.staffs;
return { staffs, pagination };
}
async list(query: PaginationQuery): Promise<any> {
const page = Number(query.page) - 1 || 0;
let limit = Number(query.limit) || 20;
const offset = page * limit;
const sort = query.sort || 'createdAt';
const archived = this.convertArchived(query.archived);
const conditions = {
...query.conditions,
...(!archived
? { deletedAt: undefined }
: { deletedAt: { $ne: undefined } })
};
const staffs = await this.model
.find(conditions)
.select(query.projections)
.skip(offset)
.limit(limit)
.sort(sort);
const totalDocuments = await this.model.countDocuments(conditions);
const result = {
staffs,
page: Number(page) + 1,
limit: Number(limit),
rowCount: Number(totalDocuments),
pageCount: Math.ceil(Number(totalDocuments) / limit)
};
return result;
}
So if role is operation for example, I want to also return users with admin
So you have both operation staff and admin staff returned.

Use $in operator, to look for users in multiple roles, like this:
if (query.role) {
conditions = { role: { "$in": [query.role, "admin"] }, 'hub.id': query.merchant
};
}

Related

How to make pagination with NodeJS?

i have a controller and i want to make pagination with 5 records per page. How can i do it with Nodejs i really need help.
const getPagination = (page, size) => {
const limit = size ? +size : 5; // Fetch 5 records
const offset = page ? page * limit : 0;// Start from page 0
return { limit, offset };
};
// Find all car with condition and how can i add pagination ?
export function findAllCar( req, res){
const name = req.query.name;
const color = req.query.color;
const brand = req.query.brand;
var condition = name ? {
name: { [Op.iLike]: `%${name}%` },
color: { [Op.iLike]: `%${color}%` },
brand: { [Op.iLike]: `%${brand}%` },
} : null;
Car.findAll({ where: condition })
.then(data => {
res.send(data);
})
.catch(err => {
res.status(500).send({
message:
err.message || "Some error occurred while retrieving CARS."
});
});
}
you need to add limit and offset inside the query.
var condition = name ? {
name: { [Op.iLike]: `%${name}%` },
color: { [Op.iLike]: `%${color}%` },
brand: { [Op.iLike]: `%${brand}%` },
} : null;
const paginate = (query, { page, pageSize }) => {
const offset = page * pageSize;
const limit = pageSize;
return {
...query,
offset,
limit,
};
};
model.findAll(
paginate(
{
where: condition
},
{ page, pageSize },
),
);
Also, you can refer to this here
you can use this
model.findAll({
limit: 5,
offset: 0,
where: {}, // conditions
});

Unable to access value of req.body

I am trying to do a PUT request to update my DB in Mongo using Axios so I can update the current week and season. In my route, I can access the req.body, but if I try to set the values, it says the values are undefined. I have tried many different things at this point. I ran into this issue as well: "Cast to Number failed".
Here is what the request looks like:
function currentWeek() {
const currentWeek =
"https://api.sportsdata.io/v3/nfl/scores/json/CurrentWeek?key=...";
axios.get(currentWeek).then((res) => {
const weekCheck = res.data;
const timeframeURL =
"https://api.sportsdata.io/v3/nfl/scores/json/Timeframes/current?key=...";
console.log(weekCheck);
axios.get(timeframeURL).then((res) => {
const timeframeWeek = res.data;
// console.log(timeframeWeek);
const thisWeek = timeframeWeek.filter(
(timeframeWeek) => timeframeWeek.Week === weekCheck
);
console.log(thisWeek);
const config = {
headers: {
"Content-Type": "application/json",
},
};
axios
.put("http://localhost:4000/api/currentweek/5ffce18e78d4742414cf279e", thisWeek, config)
.then((res) => console.log("working"))
.catch((err) => console.error(err));
console.log("Done!");
});
});
}
Here is my route:
router.put("/:_id", async (req, res) => {
const { Season, Week } = req.body;
const { _id } = req.params;
const weekField = {};
// SETING THE VALUES FROM REQ.BODY TO BE IN weekField
if (Season) weekField.Season = Season;
if (Week) weekField.Week = Week;
try {
let weekParam = await CurrentWeek.find({_id});
if (!weekParam) return res.stats(404).json({ msg: "ID in the Params does not exist" });
console.log(_id);
console.log(req.body) // RETURNS THE OBJECT CORRECTLY
console.log(weekField); // RETURNS AS AN EMPTY OBJECT
console.log("From Route ^^");
weekParam = await CurrentWeek.findOneAndUpdate(
_id,
{ $set: weekField },
{ new: true }
);
res.json(weekParam);
} catch (err) {
console.error(err.message);
res.status(500).send("Server Error");
}
});
Here is the model:
const mongoose = require('mongoose');
const CurrentWeekSchema = mongoose.Schema([{
Week: Number,
Season: Number
}]);
const CurrentWeek = module.exports = mongoose.model('currentweek', CurrentWeekSchema);
//^enables require from routes
module.exports.getCurrentWeek = function(callback, limit){
CurrentWeek.find(callback).limit(limit);
}
And here is an example of the object I am trying to take in:
[
{
SeasonType: 3,
Season: 2020,
Week: 2,
Name: 'Divisional Playoffs',
ShortName: 'Divisional',
StartDate: '2021-01-12T00:00:00',
EndDate: '2021-01-18T23:59:59',
FirstGameStart: '2021-01-16T16:35:00',
FirstGameEnd: '2021-01-16T20:35:00',
LastGameEnd: '2021-01-17T22:40:00',
HasGames: true,
HasStarted: true,
HasEnded: false,
HasFirstGameStarted: false,
HasFirstGameEnded: false,
HasLastGameEnded: false,
ApiSeason: '2020POST',
ApiWeek: '2'
}
]
I found out the issue and maybe this will be helpful for someone else in the future!
In my router file I need to change this:
const { Season, Week } = req.body;
const { _id } = req.params;
const weekField = {};
// SETING THE VALUES FROM REQ.BODY TO BE IN weekField
if (Season) weekField.Season = Season;
if (Week) weekField.Week = Week;
To this:
const data = req.body;
const { Season, Week } = data[0];
const { _id } = req.params;
const weekField = {};
// SETING THE VALUES FROM REQ.BODY TO BE IN weekField
if (Season) weekField.Season = Season;
if (Week) weekField.Week = Week;
The reason is because the data that the put request is receiving is coming in an array, so I had to set the req.body to the first object in the array.

How to dynamically generate schema for cube.js?

I have been working on a project to generate configurable dashboards.
so i have to generate schema dynamically based on an api request. is there any way to do that?
it will be very helpful if there is any working example!
There's an asyncModule function for this scenario. You can check example below:
const fetch = require('node-fetch');
const Funnels = require('Funnels');
asyncModule(async () => {
const funnels = await (await fetch('http://your-api-endpoint/funnels')).json();
class Funnel {
constructor({ title, steps }) {
this.title = title;
this.steps = steps;
}
get transformedSteps() {
return Object.keys(this.steps).map((key, index) => {
const value = this.steps[key];
let where = null
if (value[0] === PAGE_VIEW_EVENT) {
if (value.length === 1) {
where = `event = '${value[0]}'`
} else {
where = `event = '${value[0]}' AND page_title = '${value[1]}'`
}
} else {
where = `event = 'se' AND se_category = '${value[0]}' AND se_action = '${value[1]}'`
}
return {
name: key,
eventsView: {
sql: () => `select * from (${eventsSQl}) WHERE ${where}`
},
timeToConvert: index > 0 ? '30 day' : null
}
});
}
get config() {
return {
userId: {
sql: () => `user_id`
},
time: {
sql: () => `time`
},
steps: this.transformedSteps
}
}
}
funnels.forEach((funnel) => {
const funnelObject = new Funnel(funnel);
cube(funnelObject.title, {
extends: Funnels.eventFunnel(funnelObject.config),
preAggregations: {
main: {
type: `originalSql`,
}
}
});
});
})
More info: https://cube.dev/docs/schema-execution-environment#async-module

Create posts at different folder

Hi I'm using Gatsby starter blog.
I have two pages - blog and projects. Right now I have six posts, five blog posts and one project post. All the posts including the project post are created under /blog page. How do I ensure projects posts are created in /projects page instead?
I have added gatsby-source-filesystem with the path ${__dirname}/content/projects into my gatsby-config.js already.
Gatsby-node.js
const path = require(`path`)
const { createFilePath } = require(`gatsby-source-filesystem`)
exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions
if (node.internal.type === `MarkdownRemark`) {
const fileNode = getNode(node.parent);
const value = createFilePath({ node, getNode })
const parent = fileNode.sourceInstanceName;
let basePath = (parent === `blog`) ? `blog` : `projects`
createNodeField({
name: `slug`,
node,
value: `/${basePath}${value}`,
})
}
}
exports.createPages = ({ graphql, actions }) => {
const { createPage } = actions
const blogPost = path.resolve(`./src/templates/blog-post.js`)
const projectPost = path.resolve(`./src/templates/project-post.js`)
return graphql(
`
{
allMarkdownRemark(
sort: { fields: [frontmatter___date], order: DESC }
limit: 1000
) {
edges {
node {
fields {
slug
}
frontmatter {
title
}
}
}
}
}
`
).then(result => {
console.log(JSON.stringify(result, null, 4));
if (result.errors) {
throw result.errors
}
// Create blog and projects posts.
const posts = result.data.allMarkdownRemark.edges
posts.forEach((post, index) => {
const slug = post.node.fields.slug;
createPage({
path: `/${slug}`,
component: blogPost,
context: {
slug,
},
})
})
return null
})
}

Sequelize pagination

Using sequelize on my nodejs web app, I want to query posts using pagination (by date). Reading sequelize docs, they offer to use offset and limit.
Since I want to display the posts from new to old, I need to consider the date they were created. For example, if I limit the first query to 10 page, and before executing the second query a new post was created, the next query with offset of 10 will result a duplicate post from the last query.
How should I implement the pagination so it will support new entries?
The easiest way to do this is to use Sequelize's findAndCountAll
Post.findAndCountAll({
where: {...},
order: [...],
limit: 5,
offset: 0,
}).then(function (result) {
res.render(...);
});
Here, result has both the result of your query and count as result.rows and result.count. You can then increment the offset and use this for pagination.
Sequelize documentation for findAndCountAll
Try this:
const paginate = (query, { page, pageSize }) => {
const offset = page * pageSize;
const limit = pageSize;
return {
...query,
offset,
limit,
};
};
model.findAll(
paginate(
{
where: {}, // conditions
},
{ page, pageSize },
),
);
In order to avoid boilerplate code
If you want to have a stable pagination, don't paginate on row offset, since it's volatile, for the reason you mention.
You should aim for paginating on a value that is stable over time and use a where clause for filtering results. The best case would be if you have an auto-incrementing id, but the post date could also be reasonable.
Something like:
Post.findAll({
where: { createdDate: { $lt: previousDate },
limit: 10
})
You need to keep track of previousDate for this ofc. This approach also has some caveats, and you may need to combine it with client-side de-duplication.
Here is a blog post that probably has all the answers you need:
Pagination: You're (Probably) Doing It Wrong
With findAndCountAll here count is useful for pagination, from this total count we can limit as we want and also with async and await
let resAccidents = await ModalName.findAndCountAll({ where: { createdByID: employeeID }, offset: 0, limit: 10 });
this will return a count of total records as per where condition and 1st 10 records of it, then increase the value of offset to fetch further records.
You can simply do that
let limit = 10
let offset = 0 + (req.body.page - 1) * limit
Posts.findAndCountAll({
offset: offset,
limit: limit,
order: [
['date', 'ASC']
]
}).then(async result => {
return res.status(200).json({
status: true,
message: res.__('success'),
innerData: result
})
})
.catch(err => {
return validator.InvalidResponse(res, `${err}`)
})
Try this instead:
db.findAll({
offset: page_no,// your page number
limit:25,// your limit
This one solved my issue.
export const paginate = (query, schema) => {
let page = query.page ? query.page - 1 : 0;
page = page < 0 ? 0 : page;
let limit = parseInt(query.limit || 10);
limit = limit < 0 ? 10 : limit;
const offset = page * limit;
const where = {};
delete query.page;
delete query.limit;
Object.keys(schema).forEach((key) => {
schema[key] && query[key] ? (where[key] = query[key]) : null;
});
return {
where: where,
offset,
limit,
};
};
#Get()
findAll(#Query() query): unknown {
return this.model.findAll(paginate(query, {xx:1}));
}
/model?xx=yy&page=1&limit=5
var defered = Q.defer();
const offset = queryString.offset * queryString.limit;
const limit = queryString.limit;
var queryWhere = { class_id: { $ne: null }, section_id: { $ne: null } };
var searchClass = {};
var searchSection = {};
if (queryString) {
if (queryString.class && queryString.class !== "") {
searchClass = { class_id: { $eq: queryString.class } };
} else if (queryString.class && queryString.class === "") {
searchClass = { class_id: { $ne: null } };
}
if (queryString.section && queryString.section !== "") {
searchSection = { section_id: { $eq: queryString.section } };
} else if (queryString.section && queryString.section === "") {
searchSection = { section_id: { $ne: null } };
}
}
queryWhere = {
$and: [[searchClass], [searchSection]]
};
const schoolDB = require("../../db/models/tenant")(schema);
const Student = schoolDB.model("Student");
Student.findAll({
attributes: [
"id",
"first_name",
"last_name",
"profile_image_url",
"roll_number",
"emergency_contact_number"
],
offset: offset,
limit: limit,
where: queryWhere,
order: [["roll_number", "ASC"]]
})
.then(result => {
defered.resolve(result);
})
.catch(err => {
defered.reject(err);
});
Recommended using Sequelize's own operators
var defered = Q.defer();
const offset = queryString.offset * queryString.limit;
const limit = queryString.limit;
var queryWhere = { class_id: { $ne: null }, section_id: { $ne: null } };
var searchClass = {};
var searchSection = {};
if (queryString) {
if (queryString.class && queryString.class !== "") {
searchClass = { class_id: { $eq: queryString.class } };
} else if (queryString.class && queryString.class === "") {
searchClass = { class_id: { $ne: null } };
}
if (queryString.section && queryString.section !== "") {
searchSection = { section_id: { $eq: queryString.section } };
} else if (queryString.section && queryString.section === "") {
searchSection = { section_id: { $ne: null } };
}
}
queryWhere = {
$and: [[searchClass], [searchSection]]
};
const schoolDB = require("../../db/models/tenant")(schema);
const Student = schoolDB.model("Student");
Student.findAll({
attributes: [
"id",
"first_name",
"last_name",
"profile_image_url",
"roll_number",
"emergency_contact_number"
],
offset: offset,
limit: limit,
where: queryWhere,
order: [["roll_number", "ASC"]]
})
.then(result => {
defered.resolve(result);
})
.catch(err => {
defered.reject(err);
});

Resources