To query from different tables and us it in json object - json

I want to get total number of students, and per gender from each school which every school is correspond to a certain ward_id which will be selected by the user and also to get total number of schools per each ward_id passed through the api request
api url is
http://127.0.0.1:8000/api/getSchools/{ward_id}
code is below
public function getSchoolsinWard($id){
//this will be the id of ward
$array_count = [];
$array_school = [];
$schools = School::where('ward_id', $id)->get();
foreach($schools as $school){
$array_school[] = $school;
$data = count($school->grades);
foreach($school->grades as $grade){
$total = count($grade->streams);
foreach($grade->streams as $stream){
$total_students = count($stream->students);
foreach($stream->students as $student){
$array_count[] = $student;
$boys = Student::where('id', $student->id)->where('gender', 'male')->get();
$total_boys = $boys->count();
$girls = Student::where('id', $student->id)->where('gender', 'female')->get();
$total_girls = $girls->count();
}
}
}
}
$schoolsTotal = School::where('ward_id',$id)->count();
return response(['message' => 'schools in wards',
'schools'=>$array_school,
'total students'=> $array_count,
'total boys'=>$total_boys,
'total girls' => $total_girls,
'totals schools' => $schoolsTotal]);
}
the code above gives me this postman response
{
"message":"schools in wards",
"schools":[
{
"id":1,
"name":"Mivinjeni",
"educationLevel":"Secondary",
"ward_id":1,
"created_at":"2022-06-04T14:41:34.000000Z",
"updated_at":"2022-06-04T14:41:34.000000Z",
"grades":[
{
"id":1,
"name":"Form 5",
"school_id":1,
"created_at":"2022-06-04T14:47:34.000000Z",
"updated_at":"2022-06-04T14:47:34.000000Z",
"streams":[
{
"id":1,
"name":"A",
"grade_id":1,
"created_at":"2022-06-04T14:54:38.000000Z",
"updated_at":"2022-06-04T14:54:38.000000Z",
"students":[
{
"id":1,
"student_name":"Matumbu Mawe",
"gender":"male",
"stream_id":1,
"created_at":"2022-06-04T14:58:03.000000Z",
"updated_at":"2022-06-04T14:58:03.000000Z"
},
{
"id":2,
"student_name":"Lukaku Maguire",
"gender":"male",
"stream_id":1,
"created_at":"2022-06-04T14:58:46.000000Z",
"updated_at":"2022-06-04T14:58:46.000000Z"
}
]
},
{
"id":2,
"name":"B",
"grade_id":1,
"created_at":"2022-06-04T14:54:46.000000Z",
"updated_at":"2022-06-04T14:54:46.000000Z",
"students":[
]
}
]
},
{
"id":2,
"name":"Form 6",
"school_id":1,
"created_at":"2022-06-04T14:47:59.000000Z",
"updated_at":"2022-06-04T14:47:59.000000Z",
"streams":[
{
"id":3,
"name":"A",
"grade_id":2,
"created_at":"2022-06-04T14:54:52.000000Z",
"updated_at":"2022-06-04T14:54:52.000000Z",
"students":[
]
},
{
"id":4,
"name":"B",
"grade_id":2,
"created_at":"2022-06-04T14:54:56.000000Z",
"updated_at":"2022-06-04T14:54:56.000000Z",
"students":[
]
}
]
},
{
"id":3,
"name":"Form 1",
"school_id":1,
"created_at":"2022-06-04T14:49:41.000000Z",
"updated_at":"2022-06-04T14:49:41.000000Z",
"streams":[
{
"id":5,
"name":"A",
"grade_id":3,
"created_at":"2022-06-04T14:55:05.000000Z",
"updated_at":"2022-06-04T14:55:05.000000Z",
"students":[
]
},
{
"id":6,
"name":"B",
"grade_id":3,
"created_at":"2022-06-04T14:55:09.000000Z",
"updated_at":"2022-06-04T14:55:09.000000Z",
"students":[
]
}
]
},
{
"id":4,
"name":"Form 2",
"school_id":1,
"created_at":"2022-06-04T14:49:49.000000Z",
"updated_at":"2022-06-04T14:49:49.000000Z",
"streams":[
]
},
{
"id":5,
"name":"Form 3",
"school_id":1,
"created_at":"2022-06-04T14:49:53.000000Z",
"updated_at":"2022-06-04T14:49:53.000000Z",
"streams":[
]
},
{
"id":6,
"name":"Form 4",
"school_id":1,
"created_at":"2022-06-04T14:50:01.000000Z",
"updated_at":"2022-06-04T14:50:01.000000Z",
"streams":[
]
}
]
},
{
"id":2,
"name":"Miburani",
"educationLevel":"Secondary",
"ward_id":1,
"created_at":"2022-06-04T14:41:50.000000Z",
"updated_at":"2022-06-04T14:41:50.000000Z",
"grades":[
{
"id":7,
"name":"Form 4",
"school_id":2,
"created_at":"2022-06-04T14:50:10.000000Z",
"updated_at":"2022-06-04T14:50:10.000000Z",
"streams":[
]
},
{
"id":8,
"name":"Form 1",
"school_id":2,
"created_at":"2022-06-04T14:50:14.000000Z",
"updated_at":"2022-06-04T14:50:14.000000Z",
"streams":[
]
},
{
"id":9,
"name":"Form 2",
"school_id":2,
"created_at":"2022-06-04T14:50:17.000000Z",
"updated_at":"2022-06-04T14:50:17.000000Z",
"streams":[
]
},
{
"id":10,
"name":"Form 3",
"school_id":2,
"created_at":"2022-06-04T14:50:19.000000Z",
"updated_at":"2022-06-04T14:50:19.000000Z",
"streams":[
]
}
]
}
],
"total students":[
{
"id":1,
"student_name":"Matumbu Mawe",
"gender":"male",
"stream_id":1,
"created_at":"2022-06-04T14:58:03.000000Z",
"updated_at":"2022-06-04T14:58:03.000000Z"
},
{
"id":2,
"student_name":"Lukaku Maguire",
"gender":"male",
"stream_id":1,
"created_at":"2022-06-04T14:58:46.000000Z",
"updated_at":"2022-06-04T14:58:46.000000Z"
},
{
"id":3,
"student_name":"Mary Mzuri",
"gender":"female",
"stream_id":1,
"created_at":"2022-06-04T15:09:15.000000Z",
"updated_at":"2022-06-04T15:09:15.000000Z"
},
{
"id":4,
"student_name":"Anna Crush",
"gender":"female",
"stream_id":1,
"created_at":"2022-06-04T15:09:24.000000Z",
"updated_at":"2022-06-04T15:09:24.000000Z"
}
],
"total boys":0,
"total girls":1,
"totals schools":2
}
but what I wanted as the postman request is this below
{
"message":"schools in wards",
"schools":[
{
"id":1,
"name":"Mivinjeni",
"educationLevel":"Secondary",
"ward_id":1,
"total_students":21,
"total_boys":11,
"total_girls":10,
"created_at":"2022-06-04T14:41:34.000000Z",
"updated_at":"2022-06-04T14:41:34.000000Z"
},
{
"id":1,
"name":"Mivinjeni",
"educationLevel":"Secondary",
"ward_id":1,
"total_students":21,
"total_boys":11,
"total_girls":10,
"created_at":"2022-06-04T14:41:34.000000Z",
"updated_at":"2022-06-04T14:41:34.000000Z"
}
],
"total_students_in_wards":42,
"total_schools":2
}
the relation between models is Ward hasMany School hasMany Grades hasMany Stream hasMany Students

You can make use of subquery selects to get the counts for total_students, total_boys, total_girls. Then for the total_students_in_ward and total_schools you can use Collection's sum and count methods - there's no need for a separate query for the count.
public function getSchoolsinWard($id)
{
$schools = School::query()
->where('ward_id',$id)
->addSelect([
'total_students' => Student::selectRaw('count(*)')
->whereIn(
'stream_id',
Stream::select('id')->whereIn(
'grade_id',
Grade::select('id')->whereColumn('school_id', 'schools.id')
)
),
'total_boys' => Student::selectRaw('count(*)')
->whereRaw('gender = "male"')
->whereIn(
'stream_id',
Stream::select('id')->whereIn(
'grade_id',
Grade::select('id')->whereColumn('school_id', 'schools.id')
)
),
'total_girls' => Student::selectRaw('count(*)')
->whereRaw('gender = "female"')
->whereIn(
'stream_id',
Stream::select('id')->whereIn(
'grade_id',
Grade::select('id')->whereColumn('school_id', 'schools.id')
)
)
])->get();
return response()->json([
'message' => 'schools in wards',
'schools' => $schools,
'total_students_in_ward' => $schools->sum('total_students'),
'total_schools' => $schools->count()
]);
}
Laravel Docs - Eloquent - Subquery Selects
Laravel Docs - Collections - Method Sum
Laravel Docs - Collections - Method Count

Related

How do I match a key with an object with sequelize?

Current Situation
My current Sequelize Controller looks like the below:
const getSum = async(req, res) => {
const expenses = await Expense.findAll({
attributes: [
'datepick',
'itemized_expense',
[sequelize.fn('SUM', sequelize.col('expense_amount')), 'itemized_expense_sum']],
group: ['datepick', "itemized_expense"]
})
res.status(200).json(expenses)
When I use postman, the cCurrent JSON response is below:
[
{
"datepick": "2022-10-03",
"itemized_expense": "marketing",
"itemized_expense_sum": "4000"
},
{
"datepick": "2022-10-03",
"itemized_expense": "development",
"itemized_expense_sum": "8000"
},
{
"datepick": "2022-10-03",
"itemized_expense": "welfare",
"itemized_expense_sum": "1111"
},
{
"datepick": "2022-11-14",
"itemized_expense": "wages",
"itemized_expense_sum": "6000"
},
{
"datepick": "2022-10-03",
"itemized_expense": "wages",
"itemized_expense_sum": "1111"
},
{
"datepick": "2022-11-15",
"itemized_expense": "development",
"itemized_expense_sum": "1000"
}
]
The Problem
How do I change my Sequelize Controller so that the response looks like the below?
{
key: '10/20', /*this is datepick from above*/
data: {
wages: 500000, /*this is a key-value pair of itemized_expense & itemized_expense_sum from above*/
welfare: 300000,
marketing: 500000,
development: 200000,
rental: 150000
}
},
{
key: '10/21',
data: {
wages: 300000,
welfare: 400000,
marketing: 100000,
development: 500000,
rental: 250000
}
},
I was trying to use Object.key() and map but I'm not sure if that is correct
You can use lodash package to group and rearrange items:
const items = [
{
"datepick": "2022-10-03",
"itemized_expense": "marketing",
"itemized_expense_sum": "4000"
},
{
"datepick": "2022-10-03",
"itemized_expense": "development",
"itemized_expense_sum": "8000"
},
{
"datepick": "2022-10-03",
"itemized_expense": "welfare",
"itemized_expense_sum": "1111"
},
{
"datepick": "2022-11-14",
"itemized_expense": "wages",
"itemized_expense_sum": "6000"
},
{
"datepick": "2022-10-03",
"itemized_expense": "wages",
"itemized_expense_sum": "1111"
},
{
"datepick": "2022-11-15",
"itemized_expense": "development",
"itemized_expense_sum": "1000"
}
]
const groupedItems = _.groupBy(items, x => x.datepick)
const keys = Object.keys(groupedItems)
const mappedItems = keys.map(x => ({
key: x,
data: _.fromPairs(groupedItems[x].map(item => [item.itemized_expense, item.itemized_expense_sum])
)
}))
result = mappedItems
result:
[
{
"key": "2022-10-03",
"data": {
"marketing": "4000",
"development": "8000",
"welfare": "1111",
"wages": "1111"
}
},
{
"key": "2022-11-14",
"data": {
"wages": "6000"
}
},
{
"key": "2022-11-15",
"data": {
"development": "1000"
}
}
]
You can try this code in this lodash sandbox

JSON only reading first element of array

I am working on a discord bot using Typescript, and I am having a problem reading from the config.JSON file.
This is the read vars function:
fs.readFile('config.json', 'utf8', function readFileCallback(err, data){
if (err){
console.log(err);
} else {
config = JSON.parse(data);
console.log(config);
const store = config.configstore[0];
roster = config.roster[0];
}});
and this is the config.json file:
{
"configstore": [
{"prefix": "!!"},
{"wallTime": 5},
{"bufferTime": 15},
{"wall": "false"},
{"buffer": "false"},
{"lastWallTime": "-1"},
{"lastBufferTime": "-1"},
{"wallCheckRole": "Role"},
{"bubfferCheckRole": "Role"}
],
"roster": [
{"discID":"discordID","ign":"IGN"}
]
}
When I print out the raw 'config' variable it prints this:
{
configstore: [
{ prefix: '!!' },
{ wallTime: 5 },
{ bufferTime: 15 },
{ wall: 'false' },
{ buffer: 'false' },
{ lastWallTime: '-1' },
{ lastBufferTime: '-1' },
{ wallCheckRole: 'Role' },
{ bubfferCheckRole: 'Role' }
],
roster: [ { discID: 'DiscordID', ign: 'IGN' } ]
}
But when I print the store variable it prints this:
{ prefix: '!!' }
The roster is normal as well.
The roles and ids are strings, but I changed it since I don't want them leaked.
These are some examples of what you are probably trying to achieve:
let config1 = {
"configstore": [
{"prefix": "!!"},
{"wallTime": 5},
{"bufferTime": 15},
{"wall": "false"},
{"buffer": "false"},
{"lastWallTime": "-1"},
{"lastBufferTime": "-1"},
{"wallCheckRole": "Role"},
{"bubfferCheckRole": "Role"}
],
"roster": [
{"discID":"discordID","ign":"IGN"}
]
}
let config2 = {
"configstore": [
{
"prefix": "!!",
"wallTime": 5,
"bufferTime": 15,
"wall": "false",
"buffer": "false",
"lastWallTime": "-1",
"lastBufferTime": "-1",
"wallCheckRole": "Role",
"bubfferCheckRole": "Role"
}
],
"roster": [
{"discID":"discordID","ign":"IGN"}
]
}
//prints {"prefix":"!!"}
console.log("configstore1:", JSON.stringify(config1.configstore[0]));
//prints {"discID":"discordID","ign":"IGN"}
console.log("roster1:", JSON.stringify(config1.roster[0]));
//prints {"prefix":"!!","wallTime":5,"bufferTime":15,"wall":"false","buffer":"false","lastWallTime":"-1","lastBufferTime":"-1","wallCheckRole":"Role","bubfferCheckRole":"Role"}
console.log("configstore2:", JSON.stringify(config2.configstore[0]));
//prints {"discID":"discordID","ign":"IGN"}
console.log("roster2:", JSON.stringify(config2.roster[0]));

Map mongo aggregation result to array

I have a mongo query that looks like this:
db.myCollection.aggregate([ {
$group: {
_id: null,
price: {
$sum: "$price"
},
inventory: {
$sum: "$inventory"
}
}
}])
Which returns
{
"_id" : null,
"price" : 26,
"inventory" : 5,
}
I would like a query which would rather return something like this:
[
{
name: "price",
amount: 26
},
{
name: "inventory",
amount: 5
}
]
EDIT:
How would I write this in Java with Spring Data? I can group and sum but don't know how to project it?
Aggregation aggregation = newAggregation(
group("$id")
.sum("price").as("price")
.sum("inventory").as("inventory")
);
You'll need to use $project. It allows us to define which fields will be returned, as well as their format.
db.myCollection.aggregate([{
$group: {
_id: null,
price: {
$sum: "$price"
},
inventory: {
$sum: "$inventory"
}
}
},
{
$project: {
_id: 0 //removes _id from result
something: [
{name: "price", amount: "$price"},
{name: "inventory", amount: "$inventory"}
]
}
}])
That will give you:
{
"something" : [
{
"name" : "price",
"amount" : 26
},
{
"name" : "inventory",
"amount" : 5
}
]
}
You can use below aggregation
db.collection.aggregate([
{ "$project": {
"data": {
"$map": {
"input": { "$objectToArray": "$$ROOT" },
"in": { "name": "$$this.k", "amount": "$$this.v" }
}
}
}},
{ "$unwind": "$data" },
{ "$replaceRoot": { "newRoot": "$data" }},
{ "$match": { "amount": { "$ne": null }}
}
])

Angular/Ionic - How to group data from two JSON source?

I want to group data JSON into accordion list in Ionic. How can I do that with two JSON source?
Previously I did successfully with only one JSON.
I have two JSON that look like this.
The one :
{
{
"ObjectId": '001',
"ObjectName": 'Fruits'
},
{
"ObjectId": '002',
"ObjectName": 'Vegetables'
}
}
The other one :
{
{
"Name": 'Apple',
"Color": 'Red',
"ObjectId": '001'
},
{
"Name": 'Eggplant',
"Color": 'Purple',
"ObjectId": '002'
},
{
"Name": 'Banana',
"Color": 'Yellow',
"ObjectId": '001'
},
{
"Name": 'Spinach',
"Color": 'Green',
"ObjectId": '002'
},
{
"Name": 'Garlic',
"Color": 'White',
"ObjectId": '002'
},
}
Here my expected result image :
Accordion-List
I've found the solution, but i'm not sure my method is the best way.
Here is my method :
// GET DATA API
let getObjectApi = this.dataProvider.getObjectUrl();
new Promise(resolve => {
getObjectApi.subscribe(data => {
resolve(data);
this.apiObjectData = data;
// LOOPING OBJECT DATA
for (let i = 0; i < this.apiObjectData.length; i++) {
const objItem = data[i];
// GET OBJECT ITEM BY ObjectId
let getObjectItem = this.getObjectItemByObjectId('ObjectId', objItem['ObjectId']);
// PUSH THE DATA
this.apiDataResult.push({
'dataObject': objItem,
'dataObjectItem' : getObjectItem
});
}
}, err => {
console.log(err);
});
});
And here this.getObjectItemByObjectId() method :
getObjectItemByObjectId(column, value) {
let result:any = [];
let dataApi: any = [];
let getObjectItemApi = this.dataProvider.getObjectItemUrl();
new Promise(resolve => {
getObjectItemApi.subscribe(data => {
resolve(data);
dataApi = data;
for (let i = 0; i < dataApi.length; i++) {
const element = dataApi[i];
if (element[column] == value) {
result.push(element);
}
}
}, err => {
console.log(err);
});
});
return result;
}
And the result is something like this :
{
{
"dataObject": {
"ObjectId": '001',
"ObjectName": 'Fruits'
},
"dataObjectItem": {
{
"Name": 'Apple',
"Color": 'Red',
"ObjectId": '001'
},
{
"Name": 'Banana',
"Color": 'Yellow',
"ObjectId": '001'
}
}
},
{
"dataObject": {
"ObjectId": '002',
"ObjectName": 'Vegetables'
},
"dataObjectItem": {
{
"Name": 'Eggplant',
"Color": 'Purple',
"ObjectId": '002'
},
{
"Name": 'Spinach',
"Color": 'Green',
"ObjectId": '002'
},
{
"Name": 'Garlic',
"Color": 'White',
"ObjectId": '002'
}
}
}
}
That's all!
If there is a better way than my method, please let me know! And sorry if something is goes wrong. Thank you in advance !!

Iterate through JSON Object to get all objects with property

I am trying to iterate through the following JSON document in order to get the names of skating rinks:
I can get one name; however, what I am trying to do is loop through all of the entries (there are 253) and return a list of all the names.
Here is my React component:
class Patinoire extends Component {
constructor(props) {
super(props);
this.state = { patinoires: [] };
}
componentDidMount() {
var url = 'http://localhost:3000/patinoires'
fetch(url).then(function(response) {
if (response.status >= 400) {
throw new Error("Bad response from server");
}
return response.json();
})
.then(data => this.setState ({ patinoires: data.patinoires }));
}
render() {
var patinoires = this.state.patinoires;
var pjs2 = Object.values(patinoires);
var pjs3 = pjs2.map(x => x["2"].nom);
return <div>{pjs3}</div>
}
}
Right now, when using {pjs3}, I get the name of 3rd skating rink of the JSON document. How can I loop through all the entries and return the name property of all the entries?
EDIT: here is a sample of the data
{
"patinoires": {
"patinoire": [
{
"nom": [
"Aire de patinage libre, De la Savane (PPL)"
],
"arrondissement": [
{
"nom_arr": [
"Côte-des-Neiges - Notre-Dame-de-Grâce"
],
"cle": [
"cdn"
],
"date_maj": [
"2018-01-12 09:08:25"
]
}
],
"ouvert": [
""
],
"deblaye": [
""
],
"arrose": [
""
],
"resurface": [
""
],
"condition": [
"Mauvaise"
]
},
{
"nom": [
"Aire de patinage libre, Georges-Saint-Pierre (PPL)"
],
"arrondissement": [
{
"nom_arr": [
"Côte-des-Neiges - Notre-Dame-de-Grâce"
],
"cle": [
"cdn"
],
"date_maj": [
"2018-01-12 09:08:25"
]
}
],
"ouvert": [
""
],
"deblaye": [
""
],
"arrose": [
""
],
"resurface": [
""
],
"condition": [
"Mauvaise"
]
}
]
}
}
You can use Array.prototype.reduce() to flatten the result data with combination of Array.prototype.map() or Array.prototype.forEach().
Here is a running example:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
patinoires: {
patinoire: [
{
nom: ["Aire de patinage libre, De la Savane (PPL)"],
arrondissement: [
{
nom_arr: ["Côte-des-Neiges - Notre-Dame-de-Grâce"],
cle: ["cdn"],
date_maj: ["2018-01-12 09:08:25"]
}
],
ouvert: [""],
deblaye: [""],
arrose: [""],
resurface: [""],
condition: ["Mauvaise"]
},
{
nom: ["Aire de patinage libre, Georges-Saint-Pierre (PPL)"],
arrondissement: [
{
nom_arr: ["Côte-des-Neiges - Notre-Dame-de-Grâce"],
cle: ["cdn"],
date_maj: ["2018-01-12 09:08:25"]
}
],
ouvert: [""],
deblaye: [""],
arrose: [""],
resurface: [""],
condition: ["Mauvaise"]
}
]
}
};
}
renderData = () => {
const { patinoires } = this.state;
const markup = patinoires.patinoire.reduce((result, current) => {
current.nom.map(n => {
return result.push(<div>{n}</div>);
});
return result;
}, []);
return markup;
}
render() {
return <div>{this.renderData()}</div>;
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Try this:
var pjs2 = Object.values(patinoires);
var names = pjs2.reduce((accumulator, elem) => {
if (elem.patinoire) {
elem.patinoire.forEach(part => {
if(part.nom) {
part.nom.forEach((name) => accumulator.push(name));
}
});
}
return accumulator;
}, []);