Categories
discuss

ES6 Nested Grouping with Sum

I have an array like this:

[{
   id: 1,
   amount: 10,
   date: '21/01/2017'
},{
   id: 1,
   amount: 10,
   date: '21/01/2017'
},{
   id: 1,
   amount: 30,
   date: '22/01/2017'
},{
   id: 2,
   amount: 10,
   date: '21/01/2017'
},]

And I would like this to output like:

{
  '21/01/2017': {
    1: {
      amount: 20
    },
    2: {
      amount: 10
    }
  },
  '22/01/2017': {
    1: {
      amount: 30
    }
  }
}

Essentially grouping by data, nested grouping by id, whilst summing the relevant amounts.

So far I have tried using reduce, and have looked at lodash functions but have been unsuccessful. Reduce makes it easy to group by and sum by one prop, but I cannot find an elegant way to create the second level. I have created the a sandbox to demonstrate:

https://codesandbox.io/s/woj9xz6nq5

const dataToConsolidate = [{
  id: 1,
  amount: 10,
  date: '21/01/2017'
}, {
  id: 1,
  amount: 10,
  date: '21/01/2017'
}, {
  id: 1,
  amount: 30,
  date: '22/01/2017'
}, {
  id: 2,
  amount: 10,
  date: '21/01/2017'
},]

export const consolidate = (data) => {
  const result = data.reduce(function (res, obj) {

    (!(obj.date in res)) ?
      res.__array.push(res[obj.date] = obj) :
      res[obj.date].amount += obj.amount;

    return res;
  }, { __array: [] });

  return result;
};

console.log(consolidate(dataToConsolidate))

Answer

Here’s a relatively ES6-y solution using reduce:

const initial = [{ id: 1, amount: 10, date: '21/01/2017' }, { id: 1, amount: 10, date: '21/01/2017' }, { id: 1, amount: 30, date: '22/01/2017' }, { id: 2, amount: 10, date: '21/01/2017' }];

const parse = obj => obj.reduce((final, { date, id, amount }) => {
  let group = final[date] = final[date] || {};
  group[id] = group[id] || { amount: 0 };
  group[id].amount += amount;
  return final;
}, {});

const final = parse(initial);
console.log(final);

You’ll want to add appropriate logic to handle missing/erroneous date, id, or amount keys.

Categories
discuss

Firebase Analytics not working with Instant App or Normal App

I have an app that is modularized to support instant-apps.

App modules:

  • app
  • instantapp
  • base
  • main
  • detail
  • search

I tried to add Firebase by adding:

  • classpath ‘com.google.gms:google-services:3.1.1‘ → to the Project Level build.gradle
  • api “com.google.firebase:firebase-core:${versions.firebase}” → to the Base Module
  • apply plugin: ‘com.google.gms.google-services‘ → to the bottom of the Base Module
  • google-services.json → to the base module folder

When I run the non-instant app I receive the following errors:

I/FirebaseInitProvider: FirebaseApp initialization unsuccessful

E/FA: GoogleService failed to initialize, status: 10, Missing google app id value from from string resources with name google_app_id.

I/FA: App measurement is starting up, version: 11720

I/FA: To enable debug logging run: adb shell setprop log.tag.FA VERBOSE

I/FA: To enable faster debug mode event logging run:
adb shell setprop debug.firebase.analytics.app com.punpuf.chacaraselazer.app

E/FA: Missing google_app_id. Firebase Analytics disabled. See https://goo(…)

E/FA: Uploading is not possible. App measurement disabled

I/FA: Tag Manager is not found and thus will not be used

And when I run the instant app I receive the following error:

V/FA: Cancelling job. JobID: 1799580119

E/FirebaseApp: Firebase API initialization failure. (…) Caused by: java.lang.NullPointerException: Attempt to invoke interface method ‘void android.app.job.IJobScheduler.cancel(int)’ on a null object reference

I/FirebaseInitProvider: FirebaseApp initialization successful

If I add the following line: “FirebaseAnalytics.getInstance(this)“, not only does it receive the previous errors, it also crashes:

E/AndroidRuntime: FATAL EXCEPTION: main Process: com.punpuf.chacaraselazer.app, PID: 11273 java.lang.RuntimeException: Unable to start activity ComponentInfo{(…)}: java.lang.NullPointerException: Attempt to invoke interface method ‘void android.app.job.IJobScheduler.cancel(int)’ on a null object reference

So my question is how can I get Firebase Analytics to work, and not crash on both my instant and non-instant version of my app.

Although this question is a bit similar to FirebaseApp initialization unsuccessful in Android Instant apps , mine not contain the same type of errors.

Update:
I’ve created a new Firebase Project, and updated my google-services.json, but still didn’t work.

Here are my gradle files:

I’ve also tried replacing firebase analytics dependency with firebase messaging and I still received the “FirebaseApp initialization unsuccessfulerror.

Answer

I’ve had the same problem, I solved it adding the google-services.json to both base and app module and applying the google services plugin in both build.gradle files

Categories
discuss

Hibernate: initialization of complex object

I have problems with full loading of very complex object from DB in a reasonable time and with reasonable count of queries.

My object has a lot of embedded entities, each entity has references to another entities, another entities references yet another and so on (So, the nesting level is 6)

So, I’ve created example to demonstrate what I want: https://github.com/gladorange/hibernate-lazy-loading

I have User.

User has @OneToMany collections of favorite Oranges,Apples,Grapevines and Peaches. Each Grapevine has @OneToMany collection of Grapes. Each fruit is another entity with just one String field.

I’m creating user with 30 favorite fruits of each type and each grapevine has 10 grapes. So, totally I have 421 entity in DB – 30*4 fruits, 100*30 grapes and one user.

And what I want: I want to load them using no more than 6 SQL queries. And each query shouldn’t produce big result set (big is a result set with more that 200 records for that example).

My ideal solution will be the following:

  • 6 requests. First request returns information about user and size of result set is 1.

  • Second request return information about Apples for this user and size of result set is 30.

  • Third, Fourth and Fifth requests returns the same, as second (with result set size = 30) but for Grapevines, Oranges and Peaches.

  • Sixth request returns Grape for ALL grapevines

This is very simple in SQL world, but I can’t achieve such with JPA (Hibernate).

I tried following approaches:

  1. Use fetch join, like from User u join fetch u.oranges .... This is awful. The result set is 30*30*30*30 and execution time is 10 seconds. Number of requests = 3. I tried it without grapes, with grapes you will get x10 size of result set.

  2. Just use lazy loading. This is the best result in this example (with @Fetch= SUBSELECT for grapes). But in that case that I need to manually iterate over each collection of elements. Also, subselect fetch is too global setting, so I would like to have something which could work on query level. Result set and time near ideal. 6 queries and 43 ms.

  3. Loading with entity graph. The same as fetch join but it also make request for every grape to get it grapevine. However, result time is better (6 seconds), but still awful. Number of requests > 30.

  4. I tried to cheat JPA with “manual” loading of entities in separate query. Like:

    SELECT u FROM User where id=1;
    SELECT a FROM Apple where a.user_id=1;
    

This is a little bit worse that lazy loading, since it requires two queries for each collection: first query to manual loading of entities (I have full control over this query, including loading associated entities), second query to lazy-load the same entities by Hibernate itself (This is executed automatically by Hibernate)

Execution time is 52, number of queries = 10 (1 for user, 1 for grape, 4*2 for each fruit collection)

Actually, “manual” solution in combination with SUBSELECT fetch allows me to use “simple” fetch joins to load necessary entities in one query (like @OneToOne entities) So I’m going to use it. But I don’t like that I have to perform two queries to load collection.

Any suggestions?

Answer

I’m going to suggest yet another option on how to lazily fetch collections of Grapes in Grapevine:

@OneToMany
@BatchSize(size = 30)
private List<Grape> grapes = new ArrayList<>();

Instead of doing a sub-select this one would use in (?, ?, etc) to fetch many collections of Grapes at once. Instead ? Grapevine IDs will be passed. This is opposed to querying 1 List<Grape> collection at a time.

That’s just yet another technique to your arsenal.

Categories
discuss

Angular 4 input[type=’number’] prevent typing over min/max

I am trying to make a inputNumber directive which will prevent typing (not highlighting the input when value is wrong, but even typing in wrong value):

a) letters and symbols, restrict only to [0-9] b) respect min and max params c) be in relation with other such directives in the view via greaterOrEqual / lessOrEqual properties.

This is my input-number.directive.ts:

import {Directive, HostListener, Input} from '@angular/core';

@Directive({
    selector: '[inputNumber]'
})
export class InputNumberDirective {

    @Input() min: number = 0; // will be input
    @Input() max: number = 100; // will be input

    @Input() greaterOrEqual: number = 23; // will be input
    @Input() lessOrEqual: number = 77; // will be input

    @HostListener('keypress', ['$event']) sanitizeValue(event: KeyboardEvent): boolean {

        const targetVal: number = Number((<HTMLInputElement>event.target).value);

        if (event.charCode >= 48 && event.charCode < 58) {
            if (this.min !== null && targetVal < this.min) {
                return false;
            }
            if (this.max !== null && targetVal > this.max) {
                return false;
            }
            if (this.greaterOrEqual !== null && targetVal < this.greaterOrEqual) {
                return false;
            }
            return !(this.lessOrEqual !== null && targetVal > this.lessOrEqual);
        }
        return false;
    }
}

This all works in terms of preventing typing letters/symbols, but when it comes to respecting numbers limiters user is still able to type them over and my purpose to prevent this. I found some SO threads (e.g. Don’t allow typing numbers between max and min value) on this, but it didn’t help me a lot.

Answer

This is a directive (Stackblitz)I am sure will help your case, it doesn´t let other input values other than numbers but also it allows CTRL+C, CTRL+V among other usefull keys for inputs.

import { Directive, ElementRef, HostListener, Input } from '@angular/core';

@Directive({
  selector: '[NumericInput]'
})
export class NumericInput {

    constructor(private el: ElementRef) { }

    @Input() latestInputValue: number;

    @HostListener('keydown', ['$event']) onKeyDown(event) {
        let e = <KeyboardEvent> event;

            if (this.latestInputValue < 0 || this.latestInputValue > 100) {
              e.preventDefault();
            } else if ([46, 8, 9, 27, 13, 110, 190].indexOf(e.keyCode) !== -1 ||
            // Allow: Ctrl+A
            (e.keyCode === 65 && (e.ctrlKey || e.metaKey)) ||
            // Allow: Ctrl+C
            (e.keyCode === 67 && (e.ctrlKey || e.metaKey)) ||
            // Allow: Ctrl+V
            (e.keyCode === 86 && (e.ctrlKey || e.metaKey)) ||
            // Allow: Ctrl+X
            (e.keyCode === 88 && (e.ctrlKey || e.metaKey)) ||
            // Allow: home, end, left, right
            (e.keyCode >= 35 && e.keyCode <= 39)) {
              // let it happen, don't do anything
              return;
            }
            // Ensure that it is a number and stop the keypress
            if ((e.shiftKey || (e.keyCode < 48 || e.keyCode > 57)) && (e.keyCode < 96 || e.keyCode > 105)) {
                e.preventDefault();
            }
        }
}

HTML

<input NumericInput [latestInputValue]="someValue" [(ngModel)]="someValue" >
Categories
discuss

UnsupportedOperationException is thrown with Lombok Builder annotation

I am using Lombok for my project. My model looks like:

@Builder
@Data @AllArgsConstructor
public class ScreenDefinitionDTO {
    @Singular
    private List<ScreenDeclaration> screens;
}

I want to do next operation:

String screenName = ctx.screenName().getText();
ScreenDeclaration declaration = ParsingUtils
                .buildScreenDeclaration(StringUtils.trim(screenName));

Where instance is created:

public static ScreenDefinitionDTO buildEmptyScreenDTO() {
    return ScreenDefinitionDTO.builder()
            .screens(new ArrayList<>())
            .build();
}

Finally, I got:

Exception in thread "main" java.lang.UnsupportedOperationException
    at java.util.AbstractList.add(AbstractList.java:148)
    at java.util.AbstractList.add(AbstractList.java:108)

When I changed creating the instance without Lombok builder pattern everything is fine:

public static ScreenDefinitionDTO buildEmptyScreenDTO() {
    return new ScreenDefinitionDTO(new ArrayList<>());
}

I couldn’t understand what is wrong with Lombok’s builder pattern?

Answer

Due to GitHub issue

Lombok @Builder is primarily meant for immutables (and uses either Collections.unmodifiableList or Guava’s ImmutableList

that’s why you have UnsupportedOperationException

For greater certainty reproduce full code pattern where you have exception please.

Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..