How to group by on a Relation?

I have 2 objects: Object A and Object B.
An Ontology relation exists between those 2 object types.
I want to count the number of Object Bs per Object A.

How can I get the number of Object B related to each Object A via function (as I assume I will need a function) ?

I would like a statement like:
allObjectAs.groupBy(a → a.linkToObjectB).count()

One incomplete approach:
Have the object set of As. Searcharound for the object set of Bs. And then do a statement where we use both sets to filter the sides of the groupBy ?

Do you have a one-to-many or many-to-many link?

In my case, that’s NN.
But we can breakdown with the 3 cases:

  • 1<>N
  • N<>N
  • N<>1

For 1-to-many (with objectB on the many side), considering that aggregations have a limit of 10,000 buckets, I would assume you have (or pass as input) fewer than 10,000 objects A. In which case it’s probably fine to just load them all and use their primary keys for filtering Objects B, before doing the aggregation on Object B.

  public getCountOfObjectBsPerObjectA(objectSetA: ObjectSet<ObjectTypeA >): Promise<TwoDimensionalAggregation<string, Double>> {
      const objectAIds = objectSetA.all().map(objectA => objectA.primaryKey);
      const countOfObjectBsPerObjectA = Objects.search().objectTypeB().filter(
          objectB => objectB.foreignKey.exactMatch(...objectAIds)
      ).groupBy(
          objectB => objectB.foreignKey.exactValues({maxBuckets: 10_000})
      ).count();
      return countOfObjectBsPerObjectA;
  }

For many-to-many links, the objects API has a .isPresent() method for filtering that could eventually help, but I’m not sure that one can currently do any aggregation or filtering based on linked properties, so I don’t see how it could be done without loading everything in memory, like this for instance:

  public async getCountOfObjectBsPerObjectA(objectSetA: ObjectSet<ObjectTypeA>): Promise<TwoDimensionalAggregation<string, Double>> {
      const objectAs = objectSetA.all();

      const linkedObjectBs = await Promise.all(objectAs.map(
          objectA => objectA.objectTypeB.allAsync()
      ));

      const bucketsList: {key: string, value: number}[] = [];

      objectAs.forEach(
          (objectA, index) => {
              bucketsList.push({key: objectA.primaryKey, value: linkedObjectBs[index].length});
          }
      );

      return {
          buckets: bucketsList
      };
  }