Get Array Based on samecategoryname using anjularjs - angularjs

I have a Array has given below. In this array some objects contain with Key catagoryName. For each seperate CategoryName i need to get the count where ReadDate is null.
QUESTIONS HIGHLIGHTED:
Push into Array based on each Category ( category names might be 'N' number ).
Get the each category count where ReadDate is null.
.controller('testController',function($scope,$rootScope){
$rootScope.messages = [
{
"IntMessageUserId": 9,
"ReadDate": null,
"MessageSubject": "HOLY CRAP ",
"MessageText": "blah blah blah",
"Priority": 1,
"PriorityDescription": "High",
"StartDate": "2017-01-19T00:00:00",
"EndDate": "2017-07-01T00:00:00",
"IntMessageCategoryId": 36,
"CategoryName": "a New Category By Dave",
"CategoryDescription": "Only a couple",
"ActiveSw": true
},
{
"IntMessageUserId": 110,
"ReadDate": "null",
"MessageSubject": "Test_chm2",
"MessageText": "Test_chm2",
"Priority": 2,
"PriorityDescription": "Urgent",
"StartDate": "2017-01-04T00:00:00",
"EndDate": "2017-06-02T00:00:00",
"IntMessageCategoryId": 39,
"CategoryName": "Alerts",
"CategoryDescription": "Alerts",
"ActiveSw": true
},
{
"IntMessageUserId": 117,
"ReadDate": "2017-05-05T06:35:00",
"MessageSubject": "Test_chm2",
"MessageText": "Test_chm2",
"Priority": 1,
"PriorityDescription": "High",
"StartDate": "2017-01-04T00:00:00",
"EndDate": "2017-06-02T00:00:00",
"IntMessageCategoryId": 39,
"CategoryName": "Alerts",
"CategoryDescription": "Alerts",
"ActiveSw": true
},
{
"IntMessageUserId": 113,
"ReadDate": "2017-05-03T08:48:00",
"MessageSubject": "Testing PSC",
"MessageText": "Psc note that displays until May 26",
"Priority": 1,
"PriorityDescription": "High",
"StartDate": "2017-04-24T09:31:00",
"EndDate": "2017-05-26T09:31:00",
"IntMessageCategoryId": 59,
"CategoryName": "Alerts PSC",
"CategoryDescription": "Alerts PSC",
"ActiveSw": true
},
{
"IntMessageUserId": 130,
"ReadDate": null,
"MessageSubject": "17/18 Parking Pass sale dates",
"MessageText": "Parking Passes will be available for purchase for the 17/18 school year for all current Juniors starting on June 1st. Sophomores may purchase passes starting on August 1st. Sales are in person only at the school district offices. You must fill out our parking permit form, Show your current drivers license, and proof of insurance. Passes will be sold for $50.00 for the school year. \r\n\r\n",
"Priority": 0,
"PriorityDescription": "Normal",
"StartDate": "2017-05-05T10:40:00",
"EndDate": "2017-06-01T10:39:00",
"IntMessageCategoryId": 67,
"CategoryName": "High School Students",
"CategoryDescription": "High School students",
"ActiveSw": true
},
{
"IntMessageUserId": 111,
"ReadDate": "2017-05-03T08:50:00",
"MessageSubject": "Summer Sports Camps",
"MessageText": "Our summer sports camps flyers will be sent home in the next week or 2. Please check them out and see if you would like to enroll your child in a sports camp program. We encourage them to try something new, or improve their skills in an existing sport. ",
"Priority": 0,
"PriorityDescription": "Normal",
"StartDate": "2017-03-21T00:00:00",
"EndDate": "2017-05-15T00:00:00",
"IntMessageCategoryId": 69,
"CategoryName": "Athletic Department Notifications ",
"CategoryDescription": "Athletic Department.",
"ActiveSw": false
},
{
"IntMessageUserId": 131,
"ReadDate": null,
"MessageSubject": "End of Year Lunch balances",
"MessageText": "As we come to the end of our school year, a reminder that unused lunch funds will roll over to next school year and be available next year in the lunch line. If you have a student who is graduating and has unused funds, please consider donating those funds to a student in need.. You can contact the Food Service department at 513-555-5555 and we will be happy to coordinate this. Refunds of unused lunch funds can be issued for any student who's balance is greater than $5.00 Please fill out a refund form at the school office and they will be processed by our accounting department. Refund checks will be mailed within 30 days of receiving your forms in the office. Have a great summer. ",
"Priority": 0,
"PriorityDescription": "Normal",
"StartDate": "2017-05-05T10:45:00",
"EndDate": "2017-06-09T10:45:00",
"IntMessageCategoryId": 80,
"CategoryName": "Nutrition Services",
"CategoryDescription": "Nutrition Services",
"ActiveSw": true
}
];
What i tried till.
angular.forEach($rootScope.messages,function(value, key){
$scope.checkUnreadMessages(value.CategoryName);
})
var mainArray = [];
$scope.call = function(){
angular.forEach(arr, function(value, key){
var subarr = [];
subarr[value] = [];
angular.forEach($rootScope.messages, function(v, k){
if(value == v.CategoryName){
subarr[value].push(v.ReadDate);
}
})
mainArray.push(subarr);
})
}

I generally don't like to use extra library for a simple job which can be easily done in pure javascript.
https://repl.it/Hk45/2
Here is a link to a javascript compiler where you can see a solution.
Notice that all the work is done by the very simple function :
function fillOrInitiate(category, element){
if(categories[category]){
categories[category].push(element);
} else {
categories[category] = [];
categories[category].push(element);
}
}
Then just iterate through your data.
EDIT : Take care of your data, sometimes ReadDate is null and sometimes it is "null". However I took care of that in my example in the function CountReadDateNull.
You should not be able to visualize the data directly by printing final tab, but it is here as you can see on the second console.log

Why you are not using Underscore.js
Need to Extract Array Based on Category Name.
_.where( $rootScope.messages, {CategoryName: "searching category name"});
Get the each category count where ReadDate is null.
_.where( $rootScope.messages, {ReadDate: null}).length;

1) Iterate through an array of messages and check the same category name and then pushing it into new array, before that you need to group it using category name as the key.
var groupCategory = {};
angular.forEach($rootScope.messages, function (oldVal, newVal) {
if (oldVal.CategoryName === newVal.CategoryName) {
if (angular.isDefined(groupCategory[newVal.CategoryName])) {
groupCategory[newVal.CategoryName].push(newVal);
} else {
groupCategory[newVal.CategoryName] = [newVal];
}
}
});
2) Then, you can count the category group by filter/checking if ReadDate is null
var cnt = 0;
angular.forEach(sameCategoryObj, function (val) {
if(val.ReadDate === null) {
cnt++;
}
});

Related

Convert json data in simple form - Laravel chat-inbox

I am trying to get latest messages from table 'messages' for inbox
The chat is between user and owner of the item (listed on my portal)
I want to get unique data with item_id
My code is
public function inbox()
{
// $inbox = ChatMessage::distinct('item_id')->where('incoming_msg_id', auth()->user()->id)->orWhere('outgoing_msg_id', auth()->user()->id)->orderBy('msg_id', 'DESC')->get();
$inbox = Message::where('incoming_msg_id', auth()->user()->id)->orWhere('outgoing_msg_id', auth()->user()->id)->latest('msg_id')->get()->unique('item_id');
return $this->sendResponse($inbox,'Chat');
}
Result is perfect just i need is non-associative/non-object array.
Current output
{
"success": true,
"data": {
"0": {
"msg_id": 68,
"incoming_msg_id": 0,
"outgoing_msg_id": 2,
"msg": "ok let me check",
"msg_for": "hadiya",
"item_id": "13",
"msg_at": "1 day ago"
},
"1": {
"msg_id": 62,
"incoming_msg_id": 0,
"outgoing_msg_id": 2,
"msg": "test msg",
"msg_for": "hadiya",
"item_id": "1",
"msg_at": "2 days ago"
}
},
"message": "Chat"
}
Expected Output
{
"success": true,
"data": [
{
"msg_id": 68,
"incoming_msg_id": 0,
"outgoing_msg_id": 2,
"msg": "ok let me check",
"msg_for": "hadiya",
"item_id": "13",
"msg_at": "1 day ago"
},
{
"msg_id": 62,
"incoming_msg_id": 0,
"outgoing_msg_id": 2,
"msg": "test msg",
"msg_for": "hadiya",
"item_id": "1",
"msg_at": "2 days ago"
}
],
"message": "Chat"
}
It's simple by following approach you can set the http status code also (optional).
return response()->json(['chat' => $inbox], 200);
I got the solution after lots of revisions.
I got the distinct data in the best json format I was looking for...
$inbox = ChatMessage::select('msg_id','incoming_msg_id','outgoing_msg_id','msg','msg_for','item_id','msg_at')->groupBy('item_id')->where('incoming_msg_id', auth()->user()->id)->orWhere('outgoing_msg_id', auth()->user()->id)->get();
return $this->sendResponse($inbox,'Inbox');
Explanation : In Laravel 8 there is a function known as groupBy() which is use for getting distinct results.
Check the link here for more information.

Angular *ngFor: Display only unique property "category" value and lowest price in each "category"

I have an array with objects having "category" & "price" properties among others, in the Angular application I need to display only unique values of "category" property (Example: Economy, Premium & Deluxe) along with the lowest price in that category. I tried filtering it but was unable to achieve it. So can you please help how this can be achieved in Angular? Thank you.
In this example, I need to show:
Economy - Starts from 250USD
Premium - Starts from 400USD
Deluxe - Starts from 600USD
"hotelRooms": [
{
"price": {
"total": 250,
"currency": "USD"
},
"category": "Economy",
"subcategory": "single",
},
{
"price": {
"total": 350,
"currency": "USD"
},
"category": "Economy",
"subcategory": "double",
},
{
"price": {
"total": 450,
"currency": "USD"
},
"category": "Economy",
"subcategory": "family",
},
{
"price": {
"total": 400,
"currency": "USD"
},
"category": "Premium",
"subcategory": "single",
},
{
"price": {
"total": 500,
"currency": "USD"
},
"category": "Premium",
"subcategory": "double",
},
{
"price": {
"total": 600,
"currency": "USD"
},
"category": "Deluxe",
"subcategory": "single",
},
{
"price": {
"total": 700,
"currency": "USD"
},
"category": "Deluxe",
"subcategory": "double",
}
]
And in Angular:
<div *ngFor="let room of hotelRooms">
<span class="bold">{{ room.category }}</span> - Starts from {{ room.price.total}}{{ room.price.currency}}
</div>
From what I understand on this question, you need to group by category and next get the lowest price.amount for each category.
Concept (TL;DR)
Group By Category
1.1 Create an array for each category if the category array does not exist. Else reuse the created category array.
1.2 From each category array, find the lowest record based on price.amount.
1.3 If the result (from 1.2) return no value (undefined), first reset category array to empty array and add the current record to the category array. This ensures that each category will only have 1 record with the lowest price. Else just ignore it.
Data Transformation
2.1 Get the item from each category via iterate with key. It will return arrays.
2.2 Concat multiple arrays (from 2.1) into one array.
let groupByCategories = [];
groupByCategories = this.hotelRooms.reduce(function (previous, current) {
previous[current.category] = previous[current.category] || [];
let lowest = previous[current.category].find(
(x) =>
x.price.total < current.price.total
);
if (!lowest) {
previous[current.category] = [];
previous[current.category].push(current);
}
return previous;
}, Object.create(null));
this.hotelRooms = [].concat(
...Object.keys(groupByCategories).map((key) => {
return groupByCategories[key];
})
);
Sample Demo on StackBlitz

Parsing JSON to do math?

I'm new to programming (especially JSON format), so please forgive me not for using proper terminology :)
Using Python 3.7 Requests module, I receive a JSON response. To keep things simple, I made an example:
{
"Bob":
{
"Age": "15",
"LastExamGrade": "45",
},
"Jack":
{
"Age": "16",
"LastExamGrade": "58",
}
}
What I would like to do is parse the JSON responses to extract two items from each response/structure and save it to a list like this (I think this is called a tuple of tuples?):
[("Bob","45"),("Jack","58")]
Then, after receiving doing this, I will receive another similar response, such as the following (where the only thing that changed is the exam grade):
{
"Bob":
{
"Age": "15",
"LastExamGrade": "54",
},
"Jack":
{
"Age": "16",
"LastExamGrade": "70",
}
}
I want to also save the name and grade into a tuple of tuples (list).
Lastly, I would like to subtract the first exam score of each person from their last exam score, and save this into a final list, which includes the name, final exam grade, and grade improvement, like this:
[("Bob","54","9"),("Jack","67","12")]
What is the simplest way to do this using Python 3? As for my own research, I've searched all throughout StackOverflow, but couldn't find out how to parse a JSON like mine (For example, in mine, the name is outside of the curly braces), and had difficulty doing math operations for JSON items.
I'd recommend using a dedicated package for calculations like pandas:
first_exam_grades = pd.DataFrame.from_dict(first_exam_results, orient='index').astype(int)
second_exam_grades = pd.DataFrame.from_dict(second_exam_results, orient='index').astype(int)
improvements = second_exam_grades.LastExamGrade.to_frame()
improvements['Improvement'] = second_exam_grades.LastExamGrade - first_exam_grades.LastExamGrade
This will give you something that looks like this:
Now you can output it anyway you'd like
list(zip(*([improvements.index.tolist()] + [improvements[c].values.tolist() for c in improvements])))
This will give you [('Bob', 54, 9), ('Jack', 70, 12)] as you want.
One possible solution, using coroutines. Coroutine receive_message holds up to last two values LastExamGrade from the message for each student and produces list of student name, last grade and improvement over last grade:
json_messages = [
# 1st message:
{
"Bob":
{
"Age": "15",
"LastExamGrade": "45",
},
"Jack":
{
"Age": "16",
"LastExamGrade": "58",
}
},
# 2nd message
{
"Bob":
{
"Age": "15",
"LastExamGrade": "54",
},
"Jack":
{
"Age": "16",
"LastExamGrade": "70",
}
},
# 3nd message (optional)
{
"Bob":
{
"Age": "15",
"LastExamGrade": "14",
},
"Jack":
{
"Age": "16",
"LastExamGrade": "20",
}
}
]
def receive_message():
d, message = {}, (yield)
while True:
for k, v in message.items():
d.setdefault(k, []).append(v['LastExamGrade'])
d[k] = d[k][-2:] # store max last two messages
message = yield [(k, *tuple(v if len(v)==1 else [v[1], str(int(v[1])-int(v[0]))])) for k, v in d.items()]
receiver = receive_message()
next(receiver) # prime coroutine
for msg in json_messages:
print(receiver.send(msg))
Prints:
[('Bob', '45'), ('Jack', '58')]
[('Bob', '54', '9'), ('Jack', '70', '12')]
[('Bob', '14', '-40'), ('Jack', '20', '-50')]

How to update object fields inside nested array and dynamically set a field value based on some inputs

I have been working on a Mongo database for a while. The database has some visits that have this form:
[
{
"isPaid": false,
"_id": "5c12bc3dcea46f9d3658ca98",
"clientId": "5c117f2d1d6b9f9182182ae4",
"came_by": "Twitter Ad",
"reason": "Some reason",
"doctor_services": "Some service",
"doctor": "Dr. Michael",
"service": "Special service",
"payments": [
{
"date": "2018-12-13T21:23:05.424Z",
"_id": "5c12cdb9b236c59e75fe8190",
"sum": 345,
"currency": "$",
"note": "First Payment"
},
{
"date": "2018-12-13T21:23:07.954Z",
"_id": "5c12cdbbb236c59e75fe8191",
"sum": 100,
"currency": "$",
"note": "Second payment"
},
{
"date": "2018-12-13T21:23:16.767Z",
"_id": "5c12cdc4b236c59e75fe8192",
"sum": 5,
"currency": "$",
"note": "Third Payment"
}
],
"price": 500,
"createdAt": "2018-12-13T20:08:29.425Z",
"updatedAt": "2018-12-13T21:42:21.559Z",
}
]
I need to find some query to update some field of a single payment based on the _id of the visit and _id of the payment that is inside of nested array. Also when you update a payment's sum to some number so that the sum of all payments is greater than or equal to price the field isPaid is automatically updated to true.
I have tried some queries in mongoose to achieve the first part but none of them seem to work:
let paymentId = req.params.paymentId;
let updatedFields = req.body;
Visit.update(
{ "payments._id": paymentId },
{
$set: {
"visits.$": updatedFields
}
}
).exec((err, visit) => {
if (err) {
return res.status(500).send("Couldn't update payment");
}
return res.status(200).send("Updated payment");
});
As for the second part of the question I haven't really come up with anything so I would appreciate at least giving some direction on how to approach it.

CakePHP 3. Containable select

I have a many to many relation where TrainingPrograms can contain many Exercises. They are a linked via the linktable ExercisesTrainingPrograms.
I want to select certain fields from my exercises:
$trainingPrograms = $this->TrainingPrograms->find()
->contain(['Exercises' => function ($q) {
return $q
->select(['id','name','description']);
}
])
->select(['id','name','description'])
->where(['user_id' => $this->Auth->user('id')]);
The result i get looks like so:
"trainingPrograms": [
{
"id": 1,
"name": "Monday Madness",
"description": "hes",
"exercises": [
{
"id": 2,
"name": "Barbell Bench Press",
"description": "Medium grip ",
"exercise_categories_id": 2,
"exercise_difficulties_id": 1,
"created": "2015-09-16T07:07:01+0000",
"modified": "2015-09-16T07:07:01+0000",
"_joinData": {
"exercise_id": 2,
"id": 28,
"training_program_id": 1,
"created": "2015-10-07T15:45:49+0000"
}
},
{
"id": 2,
"name": "Barbell Bench Press",
"description": "Medium grip ",
"exercise_categories_id": 2,
"exercise_difficulties_id": 1,
"created": "2015-09-16T07:07:01+0000",
"modified": "2015-09-16T07:07:01+0000",
"_joinData": {
"exercise_id": 2,
"id": 35,
"training_program_id": 1,
"created": "2015-10-07T19:58:12+0000"
}
}
]
}]
As you can see i get all the fields of my exercises table, rather than the fields that i asked for. Why is that, what am I doing wrong?
belongsToMany associations do enable Query::autoFields() in case no fields have been defined via the fields option. This is necessary as the foreign key (exercise_id) is being added to the SELECT clause, which would otherwise cause no other fields to be selected (not sure in which context this is actually required).
See Source > \Cake\ORM\Association\BelongsToMany::_buildQuery()
The callbacks for the contained associations are being invoked at a later point, so that you'll have to disable autoFields() in order to be able restrict the selected fields via the query builder.
->contain(['Exercises' => function ($q) {
return $q
->select(['id','name','description'])
->autoFields(false);
}
I can't really tell whether this is the intended behavior. You may want to open an issue over at GitHub for clarification, or ask on IRC.

Resources