Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Filter array of objects by property in nested array of objects

import { AdminService } from 'src/app/services/admin.service';
import { HttpClient } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
import { Player } from './player.model';
import { LoggerService } from 'src/app/services/logger.service';
import {Sort} from '@angular/material';
import { last, map } from 'rxjs/operators';

@Component({
  selector: 'app-players',
  templateUrl: './players.page.html',
  styleUrls: ['./players.page.scss'],
})

export class PlayersPage implements OnInit {

data = [{ "_id" : { "id" : ObjectId("5cc99406babc4817f85c707e"), "email" : "[email protected]" }, "buyer" : [ "[email protected]" ], "event" : "COED A", "field" : "Main", "net" : null, "team" : null, "player" : { "overallRanking" : { "CoedRanking" : 17, "CoedRankingG" : 17, "Ranking" : 25, "RankingG" : 40 }, "shirtSize" : "S", "ranking" : { "PoolCAAG" : 31, "PoolCBB" : 17, "PoolCOpenG" : 9, "PoolWA" : 22, "PoolWAA" : 3, "PoolWOpenG" : 40 }, "avp_id" : "1013424", "adult" : true, "country" : "united states", "zip" : "10924", "state" : "ny", "city" : "goshen", "address" : "4 Maple Ave", "phone" : "8452589229", "email" : "[email protected]", "last" : "Tyles", "first" : "Julia", "completed" : true, "waivers" : ObjectId("5cc98496babc4817f85c6f65") }, "waivers" : [ { "url" : [ "https://waiverstevie.koptional.com/form/v7/[email protected]/9CYPpy1Cwa14SzS5uCb7ULX4q1HtEjvWnHYlOT3K" ], "message" : [ "Liability Waiver" ], "has_signed" : [ true ], "signatureUrl" : [ "https://s3.amazonaws.com/formsign.storage/public/signed/oqPxjdKjAUlWIqNbqtMz37Iu1FdbasvQhmvomen2.pdf" ], "email" : [ "[email protected]" ] } ] }
{ "_id" : { "id" : ObjectId("5cc99406babc4817f85c707e"), "email" : "[email protected]" }, "buyer" : [ "[email protected]" ], "event" : "COED A", "field" : "Main", "net" : null, "team" : null, "player" : { "overallRanking" : { "CoedRanking" : 32, "CoedRankingG" : 32, "Ranking" : 4 }, "shirtSize" : "XL", "ranking" : { "PoolCA" : 14, "PoolCAAG" : 7, "PoolCBB" : 17, "PoolMAA" : 3 }, "avp_id" : "1018083", "adult" : true, "country" : "united stated ", "zip" : "10924", "state" : "ny", "city" : "goshen", "address" : "4 Maple Ave", "phone" : "8452757319", "email" : "[email protected]", "last" : "lewis", "first" : "eric", "completed" : true, "waivers" : ObjectId("5cc99407babc4817f85c707f") }, "waivers" : [ { "url" : [ "https://waiverstevie.koptional.com/form/v7/[email protected]/vT15NATFszkaoy2h4KQbcW0KBMYyMLQlB6GONPIa" ], "message" : [ "Liability Waiver" ], "has_signed" : [ false ], "signatureUrl" : [ ], "email" : [ "[email protected]" ] } ] }
{ "_id" : { "id" : ObjectId("5cc994c6babc4817f85c7096"), "email" : "[email protected]" }, "buyer" : [ "[email protected]" ], "event" : "COED A", "field" : "Main", "net" : null, "team" : null, "player" : { "shirtSize" : "L", "avp_id" : "1035488", "adult" : true, "country" : "United States", "zip" : "07410", "state" : "NJ", "city" : "Fair Lawn", "address" : "45 26Th Street", "phone" : "2016757924", "email" : "[email protected]", "last" : "Duran", "first" : "Jesus", "completed" : true, "waivers" : ObjectId("5cc994c6babc4817f85c7097") }, "waivers" : [ { "url" : [ "https://waiverstevie.koptional.com/form/v7/[email protected]/LFSV6Cf02Gf2aqGZkbLr9lNWzWOuUWKzt42i5Xom" ], "message" : [ "Liability Waiver" ], "has_signed" : [ false ], "signatureUrl" : [ ], "email" : [ "[email protected]" ] }, { "url" : [ "https://waiverstevie.koptional.com/form/v7/[email protected]/LFSV6Cf02Gf2aqGZkbLr9lNWzWOuUWKzt42i5Xom" ], "message" : [ "Liability Waiver" ], "has_signed" : [ false ], "signatureUrl" : [ ], "email" : [ "[email protected]" ] } ] }
{ "_id" : { "id" : ObjectId("5cc99781babc4817f85c70b8"), "email" : "[email protected]" }, "buyer" : [ "[email protected]" ], "event" : "COED A", "field" : "Main", "net" : null, "team" : null, "player" : { "completed" : true, "first" : "Kevin", "last" : "Cole", "email" : "[email protected]", "phone" : "6034758538", "address" : "1035 S Mammoth Rd, Unit 7", "city" : "Manchester", "state" : "NH", "zip" : "03109", "country" : "United States", "adult" : true, "avp_id" : "1016822", "ranking" : { "PoolMAAG" : 3, "PoolCAG" : 17, "PoolCAAG" : 122 }, "shirtSize" : "M", "overallRanking" : { "RankingG" : 3 }, "waivers" : ObjectId("5cc99781babc4817f85c70ba") }, "waivers" : [ { "url" : [ "https://waiverstevie.koptional.com/form/v7/[email protected]/3xrsKWtVlnyjHN2xLhL1XDg3gxUDfuu0D35irIwZ" ], "message" : [ "Liability Waiver" ], "has_signed" : [ true ], "signatureUrl" : [ "https://s3.amazonaws.com/formsign.storage/public/signed/alpoVABWf4jIFERmaXj8fwhlJ1sToMRF3URjz6mB.pdf" ], "email" : [ "[email protected]" ] }, { "url" : [ "https://waiverstevie.koptional.com/form/v7/[email protected]/3xrsKWtVlnyjHN2xLhL1XDg3gxUDfuu0D35irIwZ" ], "message" : [ "Liability Waiver" ], "has_signed" : [ true ], "signatureUrl" : [ "https://s3.amazonaws.com/formsign.storage/public/signed/alpoVABWf4jIFERmaXj8fwhlJ1sToMRF3URjz6mB.pdf" ], "email" : [ "[email protected]" ] } ] }
{ "_id" : { "id" : ObjectId("5cc99b48babc4817f85c70fd"), "email" : "[email protected]" }, "buyer" : [ "[email protected]" ], "event" : "COED A", "field" : "Main", "net" : null, "team" : null, "player" : { "shirtSize" : null, "avp_id" : 1010562, "adult" : true, "zip" : "19054", "state" : "pa", "city" : "levittown", "address" : "9071 millcreek rd ", "phone" : "2152084791", "email" : "[email protected]", "last" : "Curci", "first" : "Jacquelyn", "_id" : ObjectId("5ccaf0263a2bba2ca0f83748"), "waivers" : ObjectId("5cc99b48babc4817f85c70fe"), "completed" : true, "country" : "US", "signed" : false, "shirt_size" : "N/A" }, "waivers" : [ { "url" : [ "https://waiverstevie.koptional.com/form/v7/[email protected]/eCSHwcikcmGP4DaxebeX8toP85MzlSptzvrsSCzt" ], "message" : [ "Liability Waiver" ], "has_signed" : [ true ], "signatureUrl" : [ "https://s3.amazonaws.com/formsign.storage/public/signed/lnaeaOZA2g665YYRDbg4f8zV2ZX2fEz70pI3Gx2I.pdf" ], "email" : [ "[email protected]" ] } ] }
{ "_id" : { "id" : ObjectId("5cc99b48babc4817f85c70fd"), "email" : "[email protected]" }, "buyer" : [ "[email protected]" ], "event" : "COED A", "field" : "Main", "net" : null, "team" : null, "player" : { "shirtSize" : null, "overallRanking" : { "Ranking" : 5 }, "avp_id" : 1079367, "adult" : true, "zip" : "19020", "state" : "pa", "city" : "bensalem ", "address" : "2139 joshua rd ", "phone" : "+1 (267) 581-7523", "email" : "[email protected]", "last" : "Koodathil", "first" : "James", "_id" : ObjectId("5ccaf0263a2bba2ca0f83747"), "waivers" : ObjectId("5cc99b48babc4817f85c7100"), "completed" : true, "country" : "US", "signed" : false, "shirt_size" : "N/A" }, "waivers" : [ { "url" : [ "https://waiverstevie.koptional.com/form/v7/[email protected]/jhOxsMP9ebTkhzTEaxCeiWk6HJPEtFQCrZ7nLiNz" ], "message" : [ "Liability Waiver" ], "has_signed" : [ true ], "signatureUrl" : [ "https://s3.amazonaws.com/formsign.storage/public/signed/tcbxdipuqSvculgiKkNpis6fJGx4cDkhGtSbh22T.pdf" ], "email" : [ "[email protected]" ] } ] }
{ "_id" : { "id" : ObjectId("5cc99b5ebabc4817f85c7105"), "email" : "[email protected]" }, "buyer" : [ "[email protected]" ], "event" : "COED A", "field" : "Main", "net" : null, "team" : null, "player" : { "overallRanking" : { "Ranking" : 5 }, "shirtSize" : "XS", "avp_id" : "1079953", "adult" : true, "country" : "United States", "zip" : "17257", "state" : "PA", "city" : "Shippensburg", "address" : "23 Feather Dr", "phone" : "3019919314", "email" : "[email protected]", "last" : "Morgan", "first" : "Rebecca", "completed" : true, "waivers" : ObjectId("5cc99b5ebabc4817f85c7107") }, "waivers" : [ { "url" : [ "https://waiverstevie.koptional.com/form/v7/[email protected]/jI9L3TG7BHIFyzBoL7dV1ZhSaBxSzKFQYboM4uDj" ], "message" : [ "Liability Waiver" ], "has_signed" : [ true ], "signatureUrl" : [ "https://s3.amazonaws.com/formsign.storage/public/signed/Jbe9sBWVLukgiKkUGdCWoOF4NiUjyb9TPlU0GhW2.pdf" ], "email" : [ "[email protected]" ] } ] }
{ "_id" : { "id" : ObjectId("5cc99b5ebabc4817f85c7105"), "email" : "[email protected]" }, "buyer" : [ "[email protected]" ], "event" : "COED A", "field" : "Main", "net" : null, "team" : null, "player" : { "overallRanking" : { "Ranking" : 5 }, "shirtSize" : "M", "avp_id" : "1080148", "adult" : true, "country" : "US", "zip" : "17257", "state" : "PA", "city" : "Shippensburg", "address" : "23 Feather Dr", "phone" : "7177299191", "email" : "[email protected]", "last" : "Laughman", "first" : "Jonathan", "completed" : true, "waivers" : ObjectId("5cc99b5ebabc4817f85c7106") }, "waivers" : [ { "url" : [ "https://waiverstevie.koptional.com/form/v7/[email protected]/5pGu62Cuio0pV8Pf7ZieaV2Hc0Y1c82XtoKsGdCo" ], "message" : [ "Liability Waiver" ], "has_signed" : [ true ], "signatureUrl" : [ "https://s3.amazonaws.com/formsign.storage/public/signed/nJnjHtOCrEDOqSAShDvoFrQQ2kCgRLAEGEX71yI5.pdf" ], "email" : [ "[email protected]" ] } ] }];
  displayedColumns = ["event", "field", "player", "signed", "waiver", "sendwaiver"];
 
  signed;
  unsigned;
  dummies;
  size: number;

  constructor() {
    
   }

  ngOnInit() {
    //this.pages = this.adminService.getJuliePages();
    //console.log(this.pages);
   
    //this.adminService.GetUnsignedWaivers()
    //.subscribe((data: any) => {
  
    // FILTER THE DATA TO GET COUNTS OF EACH
    // I want to filter the data to show all missing partners
      this.dummies = this.data.filter((x: any) => {
        return x.player.email === "[email protected]";
      });
      // filter the data to show who has not signed the waiver
      this.unsigned = this.data.filter((x: any) => {
          return x.waivers.has_signed === false;
      });
      // filter the data to show who has signed the waiver
      this.signed = this.data.filter((x: any) => {
          return x.waivers.has_signed === true;
      });
      console.log(this.dummies);
      console.log(this.unsigned);
      console.log(this.signed);
      this.players = this.data;
      this.players.forEach((p) => {
        p.waivers =
            p.waivers.map( w => {
              if (w.signatureUrl.length > 0) {
                w.url = w.signatureUrl;
                w.message = "View Waiver";
              }
                return w;
            });
      });

    console.log("dummies" + this.dummies + "signed", this.signed, "unsigned", this.unsigned);
    this.size = this.players.length;
    console.log(this.players);
  });
}


}
.tab-selected {
  color: #fff; /*your  text color */
  background: navy; /* your background color*/
}
.mat-table {
  border: 0px solid black;
  
  .mat-cell {
    display: flex;
    flex-direction: column;
    justify-content: center;
    text-align: left;

    .mat-cell {
      min-height: 60px;
      border-bottom: 0px solid grey;

      &:last-child {
        border-bottom: none;
      }
    }
  }
}
<ion-header>
  <ion-toolbar color="primary">
    <ion-buttons slot="start">
      <ion-back-button defaultHref="/app/admin"></ion-back-button>
    </ion-buttons>
    <ion-title>Players ({{players?.length}})</ion-title>
    <ion-subtitle>Signed: {{signed?.length}} Unsigned: {{unsigned?.length}} Dummies: {{dummies?.length}}</ion-subtitle>
  </ion-toolbar>
</ion-header>

<ion-content padding>
    <mat-table class="players-table mat-elevation-z8" [dataSource]="players">
        <ng-container matColumnDef="event">
            <mat-header-cell *matHeaderCellDef>Event</mat-header-cell>
            <mat-cell *matCellDef="let player">{{player.event}}</mat-cell>
        </ng-container>
      
        <ng-container matColumnDef="field">
            <mat-header-cell *matHeaderCellDef>Field</mat-header-cell>
            <mat-cell class="field-cell"
                      *matCellDef="let player">{{player.field}}</mat-cell>
        </ng-container>      
        <ng-container matColumnDef="player">
            <mat-header-cell *matHeaderCellDef>Player</mat-header-cell>
            <mat-cell class="player-cell" *matCellDef="let player"><a href="mailto:{{player.player.email}}">{{player.player.first}} {{player.player.last}}</a>
            </mat-cell>
        </ng-container>
        <ng-container matColumnDef="signed">
            <mat-header-cell *matHeaderCellDef> Signed? </mat-header-cell>
            <mat-cell *matCellDef="let player">
              <ng-container *ngFor="let waiver of player.waivers">
                {{waiver.has_signed}}
              </ng-container>
            </mat-cell>
          </ng-container>
          <ng-container matColumnDef="waiver">
              <mat-header-cell *matHeaderCellDef> Waiver </mat-header-cell>
              <mat-cell *matCellDef="let player">
                <ng-container *ngFor="let waiver of player.waivers">
                  <a href="{{waiver.url}}">{{waiver.message}}</a>
                </ng-container>
              </mat-cell>
            </ng-container>
  
          <ng-container matColumnDef="sendwaiver">
          <mat-header-cell *matHeaderCellDef>Send Waivers</mat-header-cell>
          <mat-cell class="sendwaiver-cell" *matCellDef="let player">
              <ion-button (click)="adminWaiverSend(player)" *ngIf="!player.waivers.has_signed"> Send Waivers
                </ion-button>
          </mat-cell>  
        </ng-container>
        <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
        
        <mat-row *matRowDef="let row; columns: displayedColumns" (click)="onRowClicked(row)"></mat-row>
        
    </mat-table> 
</ion-content>

I have the following data structure in my array of objects:

[{
event: string,
day: string,
player: {
    first: string,
    last: string,
    email: string
},
waivers: [{
    url: string,
    signatureUrl: string,
    email: string,
    message: string
}],
_id: {
  id: objectID,
  email: string
},
...]

In my component, I want to filter the data so I can display a count of three different things:

  1. this.dummies will filter the results to show any records with a player.email of [email protected]
  2. unsigned will filter the results by the waivers array's has_signed property. It should be set to false
  3. signed should filter the results by the nested array waivers' has_signed property being equal to true

this.adminService.GetUnsignedWaivers()
.subscribe((data: []) => {
   this.dummies = data.filter(x => {
      return x.player.email === "[email protected]";
   });
this.unsigned = data.filter(x => {
   x.waivers.filter(w => {
      return w.has_signed === false;
   });
});
this.signed = data.filter(x => {
   x.waivers.filter(w => {
      return w.has_signed === true;
   });
});
this.players = data;
this.players.forEach((p) => {
   p.waivers = p.waivers.map( w => {
      if (w.signatureUrl.length > 0) {
         w.url = w.signatureUrl;
         w.message = "View Waiver";
      }
      return w;
   });
});

I tried to get the above to display as code, but it wouldn't work! :(

The results of my initial query display nicely, but the counts of the filtered data don't display and log as undefined in the console.

How can I do this?

Edited to add the console.log of data: enter image description here

Looking at this, I can see why it might not work, but I don't know how to group the waivers in my aggregation so the values aren't in arrays (because they are not arrays, they are strings).

My backend aggregation query:

    Registration.aggregate([
      {$unwind: "$players"},
    {$unwind:"$players.waivers"},
    {$lookup:{
      from:"waiverrecipients",
      localField: "players.waivers",
      foreignField:"_id",
      as:"waivers"
    }},
    {$group: 
      {
        "_id":{"id": "$_id","email": "$players.email"},
        "buyer": {"$first": "$users"},
        "event": {"$first": "$event"},
        "field": {"$first": "$field"},
        "net": {"$first": "$net"},
        "team": {"$first": "$team"},
        "player": { "$first": "$players" },
        "waivers": {"$push":{
          "url": "$waivers.url",
          "message": "$waivers.message",
          "has_signed": "$waivers.has_signed",
          "signatureUrl": "$waivers.signatureUrl",
          "email": "$waivers.email"
        } }}},
    {$sort: 
      {
        "event": 1,
        "_id.id": 1,
        "_id.email": 1,
  }}
  ])
like image 786
mcadio Avatar asked May 14 '19 04:05

mcadio


People also ask

How do you filter an array with nested objects?

How do you filter nested array of objects? The filter() method creates a new array with all elements that pass the test implemented by the provided function. Approach 1: This approach uses filter() method to filter the nested object in JavaScript.

How do you filter an array of objects by key?

You can use the Object. keys() function to convert the object's keys into an array, and accumulate the filtered keys into a new object using the reduce() function as shown below. const obj = { firstName: 'Jean-Luc', lastName: 'Picard', age: 59 }; // { firstName: 'Jean-Luc', lastName: 'Picard' } Object.


1 Answers

If you just need filtered arrays and counts, you could iterate over the data array once with a forEach and check for each condition, pushing to the appropriate array if any are met. Then you have three filtered arrays and can call the .length method on any of them to get the count.

// app.component.ts

let players: any[] = [];
let dummies: any[] = [];
let unsigned: any[] = [];
let signed: any[] = [];

this.adminService.GetUnsignedWaivers().subscribe((data: any[]) => {
  data.forEach(x => {
    if (x.player.email === '[email protected]') {
      dummies.push(x);
    }

    x.waivers.forEach(waiver => {
      if (waiver.has_signed[0] === true) {
        signed.push(waiver);
      } else {
        unsigned.push(waiver);
      }

      if (waiver.signatureUrl.length > 0) {
        waiver.url = waiver.signatureUrl;
        waiver.message = "View Waiver";
      }
    }); // waiver forEach
  }); // data forEach

  this.players = data;
}); // subscribe

If you would rather use the filter method:

// app.component.ts

let players: any[];
let dummies: any[];
let unsigned: any[] = [];
let signed: any[] = [];

this.adminService.GetUnsignedWaivers().subscribe((data: any[]) => {
  let updatedData = data.map(x => {
    x.waivers.forEach(waiver) {
      if (waiver.signatureUrl.length > 0) {
        waiver.url = waiver.signatureUrl;
        waiver.message = "View Waiver";
      }
    });
    return x;
  }); // map

  this.dummies = updatedData.filter(x => {
    x.player.email === '[email protected]';
  }); // filter

  updatedData.forEach(x => {
    unsigned = unsigned.concat(x.waivers.filter(w => !w.has_signed[0]));
    signed = signed.concat(x.waivers.filter(w => w.has_signed[0]));
  }); // forEach

  this.players = updatedData;
}); // subscribe

Note that since you are using Material Table, you can add a filter with little code:

<!-- app.component.html -->

<mat-form-field>
  <input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter">
</mat-form-field>
// app.component.ts

applyFilter(filterValue: string) {
  this.dataSource.filter = filterValue.trim().toLowerCase();
}
like image 186
Jordan Stubblefield Avatar answered Sep 22 '22 14:09

Jordan Stubblefield