1.0.6666666 • Published 2 years ago

mingo-exp v1.0.6666666

Weekly downloads
-
License
MIT
Repository
github
Last release
2 years ago

mingo-exp

extend mingo with any custom function and support async code in aggregations. want to transform objects to objects? get the full power of mongo aggregation framework using mingo + the power of your own js\ts code 💪

license version npm downloads GitHub Workflow Status HitCount codecov

Installation

npm install mingo-exp

(typescript ready, no need for @types/mingo-exp :))

Example

import { Aggregator } from 'mingo/aggregator';
import { useOperators, OperatorType, PipelineOperator } from 'mingo/core';
import { $project } from 'mingo/operators/pipeline';

import { customParseExpression } from 'mingo-exp';

const { $customParse } = customParseExpression({ multiply3Numbers: (num1: number, num2: number, num3: number) => num1 * num2 * num3 });

// ensure the required operators are preloaded prior to using them.
useOperators(OperatorType.PIPELINE, { $project } as Record<string, PipelineOperator>);
useOperators(OperatorType.EXPRESSION, { $customParse });

const data = [
  { a: { b: { c: 3 }, d: 4, e: 5 } },
  { a: { b: { c: 6 }, d: 6, e: 6 } }
]

let agg = new Aggregator([
  {
    $project: {
      n1: '$a.b.c',
      n2: '$a.d',
      n3: '$a.e',
      q: { $customParse: { type: 'concat', args: ['*', '$a.b.c', '$a.d', '$a.e'] } },
      a: { $customParse: { type: 'multiply3Numbers', args: ['$a.b.c', '$a.d', '$a.e'] } }
    }
  },
]);

console.log(agg.run(data));

This will print:

[
  { n1: 3, n2: 4, n3: 5, q: '3*4*5', a: 60 },
  { n1: 6, n2: 6, n3: 6, q: '6*6*6', a: 216 }
]

async Example

import { useOperators, OperatorType, PipelineOperator } from 'mingo/core';
import { $project } from 'mingo/operators/pipeline';
import delay from 'delay';

import { generateCustomOperator, AsyncAggregator } from 'mingo-exp';

// simplified custom operator
const { $testAsync } = generateCustomOperator({
  $testAsync: async (num1: number, num2: number) => {
    await delay(1000);
    return num1 + num2;
  }
});

// ensure the required operators are preloaded prior to using them.
useOperators(OperatorType.PIPELINE, { $project } as Record<string, PipelineOperator>);
useOperators(OperatorType.EXPRESSION, { $testAsync });

const main = async ()=>{
  const data = [
    { a: { b: { c: 3 }, d: 4, e: 5 } },
    { a: { b: { c: 6 }, d: 6, e: 6 } }
  ]

  const agg = new AsyncAggregator([
      {
        $project: {
          n1: '$a.b.c',
          n2: '$a.d',
          n3: '$a.e',
          a1: { $testAsync: ['$a.d', '$a.e'] },
          a2: { $testAsync: ['$a.b.c', '$a.d'] }
        }
      },
      {
        $project: {
          a3: { $testAsync: ['$a1', '$a2'] },
        }
      }
    ]);

  console.log(await agg.run(data));
}

main();

This will print:

[
  { a3: 16 },
  { a3: 24 }
]

advanced async Example

note that $collect and $runOnce are EXPRESSION operators of this package and are compatible with AsyncAggregator, $runOnce makes promises execute only once (based on current pipe args of the promise) and the response is available for every document, $collect is similar to $push but with no need of grouping

import { useOperators, OperatorType, PipelineOperator } from 'mingo/core';
import { $project } from 'mingo/operators/pipeline';
import delay from 'delay';
import _ from 'lodash';
import { AsyncAggregator, generateCustomOperator } from '../src/index';

// simplified custom operator
const { $sendToServerInBatchesForPerformance, $lodashFind } = generateCustomOperator({
  $sendToServerInBatchesForPerformance: async (ids: string[]) => {
    // in real usage this can be a request to a server
    await delay(1000);
    return ids.map(id => ({ id, name: `king number ${id}` }));
  },
  $lodashFind: (arr: any[], predicate: any, pathInMatch: string='') => {
    return _.get(_.find(arr, predicate), pathInMatch);
  }
});

// ensure the required operators are preloaded prior to using them.
useOperators(OperatorType.PIPELINE, { $project } as Record<string, PipelineOperator>);
useOperators(OperatorType.EXPRESSION, { $lodashFind, $sendToServerInBatchesForPerformance });

const main = async () => {
  const data = [
    { a: { b: '123' } },
    { a: { b: '321' } }
  ]

  const agg = new AsyncAggregator([
    {
      $project: {
        id: '$a.b',
        idsForBatch: { $collect: '$a.b' }
      }
    },
    {
      $project: {
        id: '$id',
        response: { $runOnce: { $sendToServerInBatchesForPerformance: ['$idsForBatch'] } }
      }
    },
    {
      $project: {
        id: '$id',
        name: { $lodashFind: ['$response', { id: '$id' },'name'] }
      }
    }
  ]);

  console.log(await agg.run(data));
}

main();

This will print:

[
  { id: '123', name: 'king number 123' }, 
  { id: '321', name: 'king number 321' }
]