Skip to content

Commit

Permalink
fix($graphLookup): Handle path-based fields on initial match object.
Browse files Browse the repository at this point in the history
When the selector field is a path, create full object graph for the starting object to match.
  • Loading branch information
kofrasa committed Nov 26, 2024
1 parent 5c418e9 commit 0641f28
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 4 deletions.
12 changes: 8 additions & 4 deletions src/operators/pipeline/graphLookup.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { computeValue, Options, PipelineOperator } from "../../core";
import { Iterator, Lazy } from "../../lazy";
import { Any, AnyObject } from "../../types";
import { flatten, isNil, isString, ValueMap } from "../../util";
import { flatten, isNil, isString, setValue, ValueMap } from "../../util";
import { $lookup } from "./lookup";

interface InputExpr {
Expand Down Expand Up @@ -57,9 +57,13 @@ export const $graphLookup: PipelineOperator = (

return collection.map((obj: AnyObject) => {
// initial object to start matching
let matches: AnyObject[] = [
{ [connectFromField]: computeValue(obj, expr.startWith, null, options) }
];
const matchObj = {};
setValue(
matchObj,
connectFromField,
computeValue(obj, expr.startWith, null, options)
);
let matches: AnyObject[] = [matchObj];
let i = -1;
const map = ValueMap.init<AnyObject, number>(options.hashFunction);
do {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import { aggregate } from "../support";

// https://stackoverflow.com/a/79174521
describe("create nested top-down hierarchy using aggregation", () => {
it("passes", () => {
const relations = [
{
_id: "p_commerce_metrics_dtst_v1",
category: "dataset",
dependentOn: {
metrics: ["net_booking_count_v1"]
}
},
// Doc 2:
{
_id: "net_booking_count_v1",
category: "metric",
dependentOn: {
metrics: ["cancelled_booking_count_v1", "gross_booking_count_v1"]
}
},
// Doc 3:
{
_id: "cancelled_booking_count_v1",
category: "metric",
dependentOn: {
measures: ["hb_cancel_measure_v1"]
}
},
// Doc 4:
{
_id: "gross_booking_count_v1",
category: "metric",
dependentOn: {
measures: ["hb_booking_measure_v1"]
}
},
// Doc 5 (Not dependentOn any other document _id. Dead End):
{
_id: "hb_cancel_measure_v1",
category: "measure",
usedBy: {
metrics: ["cancelled_booking_count_v1", "more_metrics"]
}
},
// Doc 6 (Not dependentOn any other document _id. Dead End):
{
_id: "hb_booking_measure_v1",
category: "measure",
usedBy: {
metrics: ["gross_booking_count_v1", "more_metrics"]
}
}
];

const result = aggregate(relations, [
{
$match: {
_id: "p_commerce_metrics_dtst_v1"
}
},
{
$graphLookup: {
from: relations,
startWith: "$dependentOn.metrics",
connectFromField: "dependentOn.metrics",
connectToField: "_id",
depthField: "depth",
as: "dependentOnMetrics"
}
},
{
$set: {
dependentOn: {
metrics: {
$setUnion: [
{
$ifNull: ["$dependentOn.metrics", []]
},
{
$reduce: {
input: "$dependentOnMetrics.dependentOn.metrics",
initialValue: [],
in: {
$setUnion: ["$$value", "$$this"]
}
}
}
]
},
measures: {
$setUnion: [
{
$ifNull: ["$dependentOn.measures", []]
},
{
$reduce: {
input: "$dependentOnMetrics.dependentOn.measures",
initialValue: [],
in: {
$setUnion: ["$$value", "$$this"]
}
}
}
]
}
}
}
},
{
$unset: "dependentOnMetrics"
}
]);

expect(result).toEqual([
{
_id: "p_commerce_metrics_dtst_v1",
category: "dataset",
dependentOn: {
measures: ["hb_cancel_measure_v1", "hb_booking_measure_v1"],
metrics: [
"net_booking_count_v1",
"cancelled_booking_count_v1",
"gross_booking_count_v1"
]
}
}
]);
});
});

0 comments on commit 0641f28

Please sign in to comment.