Using sequelize.js get the list of all blogs `group by` `tags` from the table - express

How can we get the list of all blogs group by tags from the userblogs table
sql query below:
select max(id) as id, max(blogdetails) as blog, tags, count (tags) as tagcount from userblogs group by tags;
I have tried so far;
app.get('/service/listofblogs', async (req, res) => {
try {
const blogData = await BlogModel.findAll(
{attributes: ['blogdetails', 'tags']},
{ group: ['tags'] }
);
res.status(200).json({ blogData });
} catch (e) {
res.status(500).json({ message: e.message });
}
});

Can you try with single value instead of array?
const blogData = await BlogModel.findAll(
{attributes: ['blogdetails', 'tags']},
{ group: 'tags' }
);

Related

Strapi GROUP BY and COUNT fields with the same value

Is there any way in strapi to group by entries with the same fields and count its total?
Trying to create a Poll App which has "Response" Collection containing an "Answer" Field (enum: a, b, c, d). Would like to group responses with the same answers. Something like this:
{
"answer": "a",
"total": 3
}, {
"answer": "b",
"total": 1
}
Is it possible out of the box?
To give more context, here's its sql counterpart:
select *, count(answers) from responses group by answers
there is no known default way for groupby with entity service, however there is count query:
/src/answer/controllers/answer.js
const { createCoreController } = require("#strapi/strapi").factories;
module.exports = createCoreController("api::answer.answer", ({ strapi }) => ({
async find(ctx) {
let { query } = ctx;
let answers = await strapi.db.query("api::answer.answer").findMany({
...query,
});
answers = await Promise.all(answers.map(async (answer) => ({
...answer,
total: await strapi.db.query("api::answer.answer").count({where: '...'})
})))
return answers
},
}));
or you can use raw query like this:
let { rows } = await strapi.db.connection.raw(
`select id from posts where published_at IS NOT null order by random() limit ${count};
`);
or
let { rows } = await strapi.db.connection.raw(
`select *, count(answers) from responses group by answers;`);

Single dropdown filtering for Datatable

I've been struggling for a few days now, trying to get a single dropdown to filter my table. Upon selection of the eraId, the columns should be refreshed to only show the columns of the selected eraId.
This is how my tables looks like:
I've read a lot of examples on Datatables website or forums but I can't seem to find something working.
I have managed to create a dropdown menu containing the different EraIds as filter (I have simplified the example below with only 3 eraIds) but after selecting an entry in the dropdown, the table gets empty and the column list is not refreshed.
I think the problem is that I first retrieve the columns names, based on the eraId and then draw the table accordingly, displaying only the resources from the specific eraId. I have tried several things but did not manage.
Ideally I should callback getPlayerResourceTable with the selected eraId or update the column list with the resources on the selected eraId.
Javascript:
var columns = [];
function getPlayerResourceTable($selectedEraId) {
$.ajax({
type: "POST",
url: "./graphs.php",
data: { call_function : 'getResourceTableColumns', eraId: $selectedEraId},
success: function (data) {
data = JSON.parse(data);
columnNames = Object.keys(data.data);
for (var i in data.data) {
columns.push({data: data.data[i],
title: data.data[i]});
}
$('#playerResourceTable').DataTable( {
processing: true,
serverSide: false,
filter: true,
columns: columns,
ajax: {
url: './graphs.php',
type: 'POST',
data: { call_function: 'playerResourceTable', column_fields : data.data, eraId: $selectedEraId}
},
initComplete: function () {
this.api().columns( 0 ).every( function () {
var column = this;
var select = $('<select><option value=""></option></select>')
.appendTo( $("#playerResourceTablesWrapper .dataTables_filter"))
.on( 'change', function () {
var val = $.fn.dataTable.util.escapeRegex(
$(this).val()
);
column.search( this.value ).draw();
} );
select.append( '<option value="1">Era 1</option>' )
select.append( '<option value="2">Era 2</option>' )
select.append( '<option value="3">Era 3</option>' )
} );
}
});
}
});
}
$(document).ready(function() {
$selectedEraId = 1;
getPlayerResourceTable($selectedEraId);
} );
PHP:
getResourceTableColumns returns the column list with query similar to SELECT columnName FROM ages WHERE eraId = ?
playerResourceTable returns the resources for each column (type of resource) with query similar to SELECT ".$field_list." FROM user_resources
I also thought of removing WHERE eraId = ? in my MySQL query and filtering the columns on the client side but no luck either.
I eventually ended up separating both functions and destroying/re-creating the table when changing Era.
function getColumns($selectedEraId) {
var columns = [];
$.ajax({
type: "POST",
url: "./graphs.php",
data: { call_function : 'getResourceTableColumns', eraId: $selectedEraId},
success: function (data) {
data = JSON.parse(data);
for (var i in data.data) {
columns.push({data: data.data[i],
title: data.data[i]});
}
if ( $.fn.dataTable.isDataTable( '#playerResourceTable' ) ) { // If the table already exists, detroy it before creating it again
$('#playerResourceTable').DataTable().destroy();
}
getPlayerResourceTable($selectedEraId, columns); // Will recreate the table with the new columns
}
});
}
function getPlayerResourceTable($selectedEraId, columns_to_show) {
$city_id = 91;
$playerResourceTable = $('#playerResourceTable').DataTable( {
processing: true,
serverSide: false,
filter: true,
columns: columns_to_show,
ajax: {
url: './graphs.php',
type: 'POST',
data: { call_function: 'playerResourceTable', column_fields : columns_to_show, city_id : parseInt($city_id)}
},
initComplete: function () {
this.api().columns( 0 ).every( function () {
var column = this;
var select = $('<select id="selectEraId" ><option value=""></option></select>')
.appendTo( $("#playerResourceTablesWrapper .dataTables_filter"))
.on( 'change', function () {
var val = $.fn.dataTable.util.escapeRegex(
$(this).val()
);
column.search( this.value ).draw();
} );
dropdown_string = getEraDropdown($selectedEraId);
} );
$('#selectEraId').on('change', function() {
$selectedEraId = this.value;
columns_to_show = getColumns($selectedEraId);
});
}
});
}

Array being populated by itself

I'm having am issue with an array that seems to be getting populated with my mongoose code by itself. It's making it impossible to populate the array with modified values.
Here's the code:
router.get('/in-progress', function(req, res) {
console.log('exporting');
var dataset = [];
Intake.find({}, function(err, intakes) {
if(err){
console.log(err);
} else {
/*intakes.forEach(function(intake) {
dataset.push(
{
//requestName: intake.requestName,
requestName: 'Request Name',
status: intake.phase
}
)
});*/
return dataset;
}
}).then((dataset) => {
console.log(dataset);
const report = excel.buildExport(
[
{
heading: inProgressHeading,
specification: inProgressSpec,
data: dataset
}
]
);
res.attachment('requests-in-progress.xlsx');
return res.send(report);
});
});
As you can see, the logic to push data to "dataset" is commented out, but the console log is logging every Intake that I have in the MongoDB database. Does anyone know what I am doing wrong so that I can push my own values into "dataset"?

Find document by ID and push another subdocument

I have two Collection schemas, and I want to insert one Model instance of one schema (FA) inside an array field of the other Model schema (FP):
var FASchema = new Schema({
Timestamp: Date,
PrognostizierterBetriebswert: Number,
posFlexPot: Number,
negFlexPot: Number,
Leistungsuntergrenze: Number,
Leistungsobergrenze: Number,
posGesEnergie: Number,
negGesEnergie: Number,
Preissignal: Number,
Dummy1: Schema.Types.Mixed,
Dummy2: Schema.Types.Mixed,
Dummy3: Schema.Types.Mixed
//same: Dummy: {}
});
module.exports = mongoose.model("FA", FASchema, 'FA');
and
var FPSchema = new Schema( {
_id: String, //mongoose.Schema.Types.ObjectId,
Demonstrator: Number,
erstellt: {type: Date, 'default': Date.now},
von: Date,
bis: Date,
Fahrplanabschnitte: { type: Schema.Types.ObjectId, ref: 'FA' },
})
module.exports = mongoose.model("FP", FPSchema, 'FP');
Now, whenever I create a new FA document, I want to push the FA document into my FP collection inside the array "Fahrplanabschnitte". Either by a reference, or by a schema/nested subdocument... What is the best way to do it and how can I do it?
I call the POST method that should do the job with: router.route('/FA/FPPUT/:FP_id').put(FAController.create_and_push_to_FP_by_ID)
The function itself looks like this:
In a first step, a FA instance is created and saved in FA Collection, then the FP collection is updated and into the array "Fahrplanabschnitte", the new FA instance should be inserted. However, it does not work as planned..
exports.create_and_push_to_FP_by_ID=function(req,res) {
console.log(req.body)
var fa = new FA(req.body);
//SAVE the new instance
fa.save(function(err) {
if (err) {
console.log(err);
res.status(400);
res.send(err);
}
else {
console.log("Instanz FA in Datenbank erzeugt!");
res.status(200);
res.json({ message: 'FA-Instance created in datbase!' })
}
});
FP.findOneAndUpdate({_id: req.params.FP_id}, function(err, fp) {
if (err){
res.send(fa);
}
//res.json(fp);
fp.Fahrplanabschnitte.push(fa._id);
})
};
What am I doing wrong?
You are going wrong here
`fp.Fahrplanabschnitte.push(fa._id); //does't make sense at all`
above line doesn't do or update anything to the mongodb database...
you need to use $push operator to update the collection in the
database
exports.create_and_push_to_FP_by_ID=function(req,res) {
console.log(req.body)
var fa = new FA(req.body);
//SAVE the new instance
fa.save(function(err, fa) {
if (err) {
console.log(err);
res.status(400);
res.send(err);
}
else {
console.log("Instanz FA in Datenbank erzeugt!");
FP.findOneAndUpdate({_id: req.params.FP_id}, { $push: {
Fahrplanabschnitte: fa._id } } function(err, fp) {
if (err){
return res.send(fa);
}
res.status(200);
res.json({ message: 'FA-Instance created in datbase!' })
})
}
});
};

How use dynamic routes to find people in my mongoose database with node.js

app.get('/admin/reservas/:param', function(req, res) {
var param = req.param("param");
console.log(param);
mongoose.model('Something').findOne(
{
id: param
}, function(err, obj) {
res.send(obj);
console.log(obj);
}
);
});
I have this route, and this EJS:
<% for(var i = 0; i < data.length; i++) { %>
<td> <a href= <%="/admin/reservas/" + data[i].id + ""%>><%= data[i].id %></a></td>
<td> <a href= <%="/admin/reservas/" + data[i].name + ""%>><%= data[i].name %></a></td>
<% } %>
And is fine, when i click in the id, i find what the id in the db that i want, but I want to be able to find by the name too.
So i was trying to change the routes:
app.get('/names/:param', function(req, res) {
var param = req.param("param");
console.log(param);
mongoose.model('Something').findOne(
{
id: param,
name: param
}, function(err, obj) {
res.send(obj);
console.log(obj);
}
);
});
but is returning anything, both the id and the name
MongoDB query arguments are by default always a logical and condition. In order to use a logical or there is the $or operator:
app.get('/admin/reservas/:param', function(req, res) {
var param = req.param("param");
console.log(param);
mongoose.model('Something').findOne(
{
"$or": [
{ id: param },
{ name: param }
]
}, function(err, obj) {
res.send(obj);
console.log(obj);
}
);
});
The $or operator takes an array of query documents to consider the conditions of. It is a "short circuit" match where the first condition to evaluate as true makes the statement true.
At least that would be true if not of a specific problem here. See _id and it's id alias is a special value to both MongoDB and Mongoose. By default this will try to "cast" to an ObjectID type but it cannot if the string supplied is invalid, such as "fred" for example.
This would cause an exception as the query arguments are supplied. So the bottom line rule is your cannot "mix types" in an $or condition in this way with something that would not survive the conversion from String. You would have to do it "logically" in a different way by testing the value
for what it is:
app.get('/admin/reservas/:param', function(req, res) {
var param = req.param("param");
console.log(param);
var query = {};
try {
var id = mongoose.mongo.ObjectID(param);
query = { "id": id };
} catch {
query = { "name": param };
}
mongoose.model('Something').findOne(
query, function(err, obj) {
res.send(obj);
console.log(obj);
}
);
});
That means that the query is now built in a way that mongoose will parse it considering the schema "types" to apply then there is no error since the decision of which field to query on was made elsewhere.
Alternately of course you can "bypass" the mongoose method behavior and just use the raw driver:
app.get('/admin/reservas/:param', function(req, res) {
var param = req.param("param");
console.log(param);
var id ="";
try {
id = mongoose.mongo.ObjectID(param);
}
mongoose.model('Something').collection.findOne(
{
"$or": [
{ id: id },
{ name: param }
]
}, function(err, obj) {
res.send(obj);
console.log(obj);
}
);
});
But of course you need to do the type conversion yourself and not only for "testing" otherwise even a correct "String" value representing an ObjectID would not work.