0.4.9 • Published 10 days ago

@jayalfredprufrock/mongoes v0.4.9

Weekly downloads
-
License
MIT
Repository
github
Last release
10 days ago

MongoES

Meet the tiny and tasty TypeScript library for best-effort conversion of MongoDB search queries into equivalent ElasticSearch queries. Supports most queries that make sense within the context of ES and also provides support for custom operations. Zero dependencies.

npm i @jayalfredprufrock/mongoes

Usage

import { convertQuery } from 'mongoes';

const query = convertQuery({
    $and: [
        { type: 'fruit' },
        {
            $or: [{ name: 'mango' }, { name: 'el mango' }],
        },
    ],
});

// query
// {
//    bool: {
//        must: [
//            { term: { type: 'fruit' } },
//            {
//                bool: {
//                    should: [
//                          { term: { name: 'mango' } },
//                          { term: { name: 'el mango' } }
//                    ],
//                    minimum_should_match: 1
//                },
//            },
//        ],
//    },
// }

Built-in Operators

See MongoDb docs for a list of operators and options. Also check out the sift.js library, which provides support for evaluating/filtering in-memory objects using this same mongo-style syntax. A major motiviation for MongoES was to have a single filtering/querying syntax that could be used both against ES indexes and in-memory objects.

Custom Operators

OOTB, mongoes includes a few operators that aren't a part of the MongoDB query specification:

  • $like - Maps to ES Wildcard queries. Both * and % can be used to match zero or more characters, while ? can be used to match exactly one character. Like the $regex operator, set $options to "i" to set the ES option case_insensitive to true. Note that exactly how ElasticSearch treats case sensitivity is also dependent on the underlying field mapping.
  • $prefix - Maps to ES Prefix queries. Similar to $like, supports passing "i" to $options for case insensitivity.
  • $ids - Maps to ES "ids" query. The operand is an array of document _ids. The field name is not used when constructing the ES query, however it is used to specify a document-level id field for supporting Sift queries.
  • $empty - Works just like $exists, but does not consider empty strings (after trimming) to exist.

Additionally, users can create their own custom operations by including an object of operator functions:

const operators = {
    $fuzz: (field: string, operand: string, options?: { fuzziness?: number | 'AUTO' }) => {
        return { fuzzy: { [field]: { value: operand, ...options } } };
    },
};

const query = convertQuery({ name: { $fuzz: 'Mangeos', $options: { fuzziness: 2 } } }, { operators });

// query
// {
//    bool: {
//        must: {
//            fuzzy: {
//                name: {
//                    value: 'Mangeos',
//                    fuzziness: 2
//                }
//            }
//        }
//    }
//}

Gotchas

  • Assumes valid mongodb queries. No guarantees about what is returned/thrown for invalid mongodb queries. Please create an issue if there is specific invalid syntax that you think should be handled differently at runtime.
  • Uses term queries for all text related operators. Might provide support for "match" queries if there is interest.
  • Not all operators translate cleanly to ES. The following operators are unsupported: $where, $type, $size, $mod
  • $elemMatch translates to a nested query
  • $or queries always translate into should + minimum_should_match=1. This allows adjacent $and operators (including implicit) to work as expected.
  • $all operator within $elemMatch is converted to must + multiple term expressions.
  • No guarantee about the syntactical stability of queries to allow future optimizations without a major version bump
  • Some attempt made to produce compact representations: e.g. removes redundant { bool: { must: { bool: exp }}}
  • Queries involving regular expressions or wildcards (i.e. $regex, $like, $prefix, etc. ) should be used sparingly since they are significantly more expensive than simpler query operators.
  • Lucene's regex engine (mostly PCRE) is not fully compatible with JavaScript's. Of particular note:
    • only support for i flag (case insensitive)
    • no support for ^ and $ (start/end anchors)
0.4.9

10 days ago

0.4.8

10 days ago

0.4.5

10 days ago

0.4.4

10 days ago

0.4.7

10 days ago

0.4.6

10 days ago

0.4.3

10 days ago

0.4.2

10 days ago

0.4.1

1 month ago

0.4.0

1 month ago

0.3.2

3 months ago

0.1.0

9 months ago

0.3.0

9 months ago

0.0.3

9 months ago

0.2.0

9 months ago

0.1.1

9 months ago

0.0.2

10 months ago

0.3.1

8 months ago

0.0.1

12 months ago