@monlite/core 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -0
- package/dist/index.cjs +50 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +23 -1
- package/dist/index.d.ts +23 -1
- package/dist/index.js +50 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -317,6 +317,28 @@ await users.distinct("age", { role: "admin" }); // [28, 31]
|
|
|
317
317
|
await users.distinct("tags"); // ["a", "b", "c"]
|
|
318
318
|
```
|
|
319
319
|
|
|
320
|
+
### Joins (`$lookup` / `$unwind`)
|
|
321
|
+
|
|
322
|
+
Pull in related documents from another collection with a `lookup` on `findMany`
|
|
323
|
+
— a left join, run as **two queries (no N+1)**, in either storage mode:
|
|
324
|
+
|
|
325
|
+
```ts
|
|
326
|
+
// Attach each user's orders as an array ($lookup):
|
|
327
|
+
await db.collection("users").findMany({
|
|
328
|
+
lookup: { from: "orders", localField: "_id", foreignField: "user_id", as: "orders" },
|
|
329
|
+
});
|
|
330
|
+
// → [{ _id: "u1", name: "Ali", orders: [ {…}, {…} ] }, …]
|
|
331
|
+
|
|
332
|
+
// Flatten to one row per match with `unwind` ($unwind); use "preserve" to keep
|
|
333
|
+
// rows that have no match (left-outer):
|
|
334
|
+
await db.collection("orders").findMany({
|
|
335
|
+
lookup: { from: "users", localField: "user_id", foreignField: "_id", as: "user", unwind: true },
|
|
336
|
+
});
|
|
337
|
+
// → [{ _id: "o1", user_id: "u1", user: { _id: "u1", name: "Ali" } }, …]
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
Pass an array of specs to join several collections at once.
|
|
341
|
+
|
|
320
342
|
---
|
|
321
343
|
|
|
322
344
|
## Live queries (reactivity)
|
package/dist/index.cjs
CHANGED
|
@@ -1153,7 +1153,56 @@ var Collection = class {
|
|
|
1153
1153
|
return this.db.prepare(`SELECT 1 FROM "${this.name}" WHERE ${clause} LIMIT 1`).get(...params) != null;
|
|
1154
1154
|
}
|
|
1155
1155
|
async findMany(args = {}) {
|
|
1156
|
-
return this.findManyCore(args);
|
|
1156
|
+
if (!args.lookup) return this.findManyCore(args);
|
|
1157
|
+
const specs = Array.isArray(args.lookup) ? args.lookup : [args.lookup];
|
|
1158
|
+
let rows = this.findManyCore({
|
|
1159
|
+
...args,
|
|
1160
|
+
select: void 0,
|
|
1161
|
+
lookup: void 0
|
|
1162
|
+
});
|
|
1163
|
+
for (const spec of specs) rows = await this.applyLookup(rows, spec);
|
|
1164
|
+
if (args.select) {
|
|
1165
|
+
rows = rows.map((r) => {
|
|
1166
|
+
const projected = project(r, args.select);
|
|
1167
|
+
for (const spec of specs) projected[spec.as] = r[spec.as];
|
|
1168
|
+
return projected;
|
|
1169
|
+
});
|
|
1170
|
+
}
|
|
1171
|
+
return rows;
|
|
1172
|
+
}
|
|
1173
|
+
/** Resolve one `$lookup` spec against already-fetched rows (2 queries, no N+1). */
|
|
1174
|
+
async applyLookup(rows, spec) {
|
|
1175
|
+
const localValues = [
|
|
1176
|
+
...new Set(
|
|
1177
|
+
rows.map((r) => r[spec.localField]).filter((v) => v !== void 0 && v !== null)
|
|
1178
|
+
)
|
|
1179
|
+
];
|
|
1180
|
+
const foreign = localValues.length ? await this.mon.collection(spec.from).findMany({
|
|
1181
|
+
where: { [spec.foreignField]: { in: localValues } }
|
|
1182
|
+
}) : [];
|
|
1183
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
1184
|
+
for (const f of foreign) {
|
|
1185
|
+
const key = f[spec.foreignField];
|
|
1186
|
+
const list = byKey.get(key);
|
|
1187
|
+
if (list) list.push(f);
|
|
1188
|
+
else byKey.set(key, [f]);
|
|
1189
|
+
}
|
|
1190
|
+
if (spec.unwind) {
|
|
1191
|
+
const out = [];
|
|
1192
|
+
for (const r of rows) {
|
|
1193
|
+
const matches = byKey.get(r[spec.localField]) ?? [];
|
|
1194
|
+
if (matches.length === 0) {
|
|
1195
|
+
if (spec.unwind === "preserve") out.push({ ...r, [spec.as]: null });
|
|
1196
|
+
} else {
|
|
1197
|
+
for (const m of matches) out.push({ ...r, [spec.as]: m });
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
return out;
|
|
1201
|
+
}
|
|
1202
|
+
return rows.map((r) => ({
|
|
1203
|
+
...r,
|
|
1204
|
+
[spec.as]: byKey.get(r[spec.localField]) ?? []
|
|
1205
|
+
}));
|
|
1157
1206
|
}
|
|
1158
1207
|
async findFirst(args = {}) {
|
|
1159
1208
|
const rows = await this.findMany({ ...args, take: 1 });
|