vazco/sparrowql
Declarative MongoDB aggregations.
Contribute | Usage | Documentation | Playground | FAQ
- Automatic
$lookup
only if needed - Declarative pipelines generation
- Optimized for multi-collection queries
SparrowQL was created to make your work with multi-collection queries much easier and convenient. SparrowQL is an alternative way to make your aggregation pipeline easier to read and maintain. The most significant profits are the less time spent on pipelining queries and a boost on performace.
npm install sparrowql
Here are a few easy steps to start your work with sparrowql.
If you want to create new queries with SparrowQL, you need a query build function
import { build } from "sparrowql";
Basic example
Imagine you have a simple db model:
And a some fixtures for it:
const blogs = [{ _id: 0, ownerId: 3, topic: "Best blog!" }];
const posts = [
{ _id: 0, authorId: 0, blogId: 0, title: "Being fast for dummies" },
{ _id: 1, authorId: 0, blogId: 0, title: "Being declarative" },
{ _id: 2, authorId: 1, blogId: 0, title: "Amazing!" },
{ _id: 3, authorId: 2, blogId: 0, title: "A sparrow, really?" },
{ _id: 4, authorId: 1, blogId: 0, title: "Best!" },
{ _id: 5, authorId: 1, blogId: 0, title: "Superb!" }
];
const users = [
{ _id: 0, name: "SparrowQL", about: "Declarative aggregations" },
{ _id: 1, name: "Random #1", about: "Node.js developer" },
{ _id: 2, name: "Random #2", about: "Bird lover" },
{ _id: 3, name: "BlogOwner", about: "Owner of the blog" }
];
Now you want to create a query to get all the data you need e.g.
Let's say you want to receive all the posts' titles written on blogs with blogs' topics. What do we need to make it work? To build a simple pipeline, you need a few arguments to the build
function:
projection
- pick the fields you need
const projection = {
blogTopic: "Blogs.topic",
postTitle: "Posts.title"
};
relations
- define relations between collections
const relations = [
{ to: "Blogs", from: "Posts", foreign: "_id", local: "blogId" },
{ to: "Users", from: "Blogs", foreign: "_id", local: "ownerId" },
{ to: "Users", from: "Posts", foreign: "_id", local: "authorId" }
];
start
- what is the main collection you want to start from
const start = "Posts";
Now you only need to build your new pipeline:
const pipeline = build({ projection, relations, start });
const results = await Posts.aggregate(pipeline).toArray();
// Results
[
{ blogTopic: "Best blog!", postTitle: "Being fast for dummies" },
{ blogTopic: "Best blog!", postTitle: "Being declarative" },
{ blogTopic: "Best blog!", postTitle: "Amazing!" },
{ blogTopic: "Best blog!", postTitle: "A sparrow, really?" }
];
Aliases - example
SparrowQL works correctly only on directed trees - in this case, you want to create a query which takes all the posts that were posted on someone's blog and the name of the blog owner. To make it work, you need to use aliases. Here is an example:
The only thing to do is to create aliases:
const aliases = {
Authors: "Users",
Owners: "Users"
};
And here is the rest of the query:
const projection = {
ownerName: "Owners.name",
postTitle: "Posts.title"
};
const start = "Posts";
const pipeline = build({ aliases, projection, relations, start });
const results = await Posts.aggregate(pipeline).toArray();
// Results
[
{ ownerName: "BlogOwner", postTitle: "Being fast for dummies" },
{ ownerName: "BlogOwner", postTitle: "Being declarative" },
{ ownerName: "BlogOwner", postTitle: "Amazing!" },
{ ownerName: "BlogOwner", postTitle: "A sparrow, really?" }
];
SparrowQL also may provide you with few other stages you might want to use:
- sort - handle sort, which maps to $sort directly
- query - handle query, which maps to $match directly*
- limit - handle limit, which maps to $limit and $skip directly*
* They may result in more than one phase.
More complex example with other stages
Example
const limit = 1;
const projection = {
blogOwnerName: "Owners.name",
postAuthorName: "Authors.name",
postTitle: "Posts.title"
};
const query = { "Authors.name": "Random #1" };
const skip = 1;
const sort = { "Posts.title": -1 };
const start = "Posts";
const pipeline = build({
aliases,
limit,
projection,
query,
relations,
skip,
sort,
start
});
const results = await Posts.aggregate(pipeline).toArray();
[
{
blogOwnerName: "BlogOwner",
postAuthorName: "Random #1",
postTitle: "Best!"
}
];
If you want to see a more detailed description, please see this article or check all the examples to get familiar with SparrowQL
Like every package maintained by Vazco, sparrowql package is MIT licensed.