עידו פרלמוטר (Ido Perlmuter) > MQUL > MQUL::Reference

Download:
MQUL-0.004.tar.gz

Annotate this POD

Website

View/Report Bugs
Source  

NAME ^

MQUL::Reference - Describes the MQUL query and update language

VERSION ^

version 0.004

INTRODUCTION ^

The MQUL (pronounced "umm, cool") language is heavily based on MongoDB's query and update language. While I don't intend to make it 100% compatible with it, it is very nearly so, with only some minor differences which are mostly additions rather than behavioral changes.

The language deals with two subjects: queries and updates. Queries are used to match documents (in the MongoDB sense of the word; documents are just hash-refs in the Perl world), while updates are used to modify the attributes of a document.

QUERY STRUCTURES ^

A query is a hash-ref whose keys are attributes, and values are constraints. A document needs to meet the constraints of every attribute in the query hash-ref in order to match.

THE EQUALITY CONSTRAINT

The simplest constraint a query hash-ref can define is an equality constraint, which checks if the value of a certain attribute in a document equals the value defined by the constraint. For example:

        $query = { title => 'Freaks and Geeks' }

A document will match this query hash-ref if it has a title attribute, whose value equals 'Freaks and Geeks'.

The equality attribute in MongoDB actually works with arrays too, but the behavior is a bit different: If the document has the constrained attribute, but this attribute is an array, the document will match the constraint if that array has the value in it. For example, the query:

        $query = { tv_shows => 'Freaks and Geeks' }

Will match the following document:

        $document = { tv_shows => ['Freaks and Geeks', 'Undeclared', 'How I Met Your Mother'] }

MQUL extends the equality constraint even further than MongoDB. In MQUL, the value of the constraint doesn't have to be a scalar, but can actually be a data structure such as an array or hash reference. For example:

        $query = {
                numbers => {
                        one => 1,
                        two => 2,
                        three => 3,
                }
        }

A document will match this constraint if it has the 'numbers' attribute, with exactly the same hash-ref from the query as its value. In order to compare the document's structure with the constraint structure, MQUL uses Data::Compare.

The equality constraint in MQUL also supports comparing MongoDB::OID objects and MorboDB::OID objects (which are used by MorboDB, my in-memory "clone" of MongoDB).

THE LARGER/SMALLER THAN CONSTRAINTS

Some other simple constrains require that an attribute will be larger or smaller than a certain value. Mostly, the comparison will be mathematical (e.g. 5 > 3 or 3 <= 5). However, the comparison can also be alphanumerical (e.g. 'and' lt 'bob' or 'max' ge 'max').

For example:

        $query = { number => { '$gte' => 2, '$lt' => 5 } }

Here, we're asking documents to have the number attribute, with a number that's either larger (or equal) than 2, and lower than 5 (so 2, 3 and 4 are acceptable).

As you can see, this time the constraints are provided to the 'number' attribute in the query structure as a hash-ref with two constraints. The fact that we're giving more than one constraint on the same attribute isn't the reason for using a hash-ref. A hash-ref is used for all of the constraints in the language, except of course the equality constraint described before, so the hash-ref can also have only one constraint, like:

        $query = { string => { '$lt' => 'bob' } }

The following larger/smaller than constraints are available:

THE NON-EQUALITY CONSTRAINT (AND THE SECOND EQUALITY CONSTRAINT)

Sometimes you want to make sure a certain attribute's value does not equal some specific value. This is where the $ne constraint is useful. Once again, the comparison can either be mathematical (in which case it translates to the != operator in Perl), or alphanumerical (in which case it translates to the ne operator in Perl).

        $query = {
                title => { '$ne' => 'Freaks and Geeks' },
                year => { '$ne' => 1999 },
        }

The following document will match this constraint:

        $document = {
                title => 'Undeclared',
                year => 2001,
        }

The $ne constraint is somewhat different than the equality constraint described earlier. It cannot work with arrays, and will not compare complex data structures.

For completeness, MQUL also provides a second equality constraint, called $eq, which is exactly the opposite of $ne. However, this equality constraint, just like $ne, does not work with arrays and complex data structures, nor with MongoDB::OID and MorboDB::OID objects.

THE EXISTS (OR NOT EXISTS) CONSTRAINTS

Sometimes you just wanna make sure an attribute exists (or doesn't) in a document, whatever the value (even undefined). In such cases, the $exists constraint can be used:

        $query = { imdb_score => { '$exists' => 1 } }

The above example will only match documents that have the 'imdb_score' attribute.

        $query = { imdb_score => { '$exists' => 0 } }

This, however, will only match documents that don't have the 'imdb_score' attribute.

THE MODULO CONSTRAINT

The $mod constraint can be used for fast modulo queries on a certain attribute. For example:

        $query = { number => { '$mod' => [2, 0] } }

This constraint asks that $document->{number} % 2 == 0.

THE IN OR NOT IN CONSTRAINTS

Sometimes you want to make sure the value of a certain attribute will be (or won't be) one of a predefined set of acceptable (or not acceptable) values. For this, the $in and the $nin constraints can be used. For example:

        $query = {
                title => { '$in' => ['Freaks and Geeks', 'Undeclared'] },
                genre => { '$nin' => ['Drama', 'Documentary'] },
        }

This query will only match documents whose 'title' attribute is either 'Freaks and Geeks' or 'Undeclared', and whose 'genre' attribute is neither 'Drama' nor 'Documentary'.

THE SIZE CONSTRAINT

If your documents have an attribute which holds an array or a hash, you can match those whose arrays/hashes are of a certain size. For example:

        $query = { tags => { '$size' => 2 } }

This will match documents that have the 'tags' attribute, with either an array of two values, or a hash with two keys.

THE ALL CONSTRAINT

The $all constraint is used to make sure an array attribute has all values in a set of predefined values (it can have more values though). For example:

        $query = { tags => { '$all' => [qw/love hate/] } }

This will only match documents that have the 'tags' attribute with an array that has both 'love' and 'hate' in it. This document will match:

        $document = { tags => [qw/love indifference hate/] }

THE TYPE CONSTRAINT

The $type constraint can be used when you need a certain attribute or attributes to have values of a certain specific type. In MongoDB, the types are numbered (like 2 for strings, 4 for arrays, etc.), which is really hard to remember. In MQUL, however, the types are named, plus (mostly due to differences between the Perl world and the MongoDB world) the actual types available are somewhat different.

But before we go into the list of available types, let's see a simple example:

        $query = {
                tags => { '$type' => 'array' },
                imdb_score => { '$type' => 'int' },
        }

This will only match documents that have a 'tags' attribute with arrays as their values, and an 'imdb_score' attribute with integers (but not floats) as the values. So, the following document will match:

        $document_that_matches = {
                title => 'Fake Title',
                tags => [qw/comedy drama/],
                imdb_score => 8,
        }

While this document won't:

        $document_that_doesnt = {
                title => 'Another Fake Title',
                tags => [qw/mystery thriller/],
                imdb_score => 8.5,
        }

Even though 'tags' is an array, 'imdb_score' is not an integer, and thus the second document will not match.

The following types are available:

OR QUERIES

As you've probably realized by now, a document needs to match every constraint in the query hash-ref. If we were to translate a query hash-ref into an SQL WHERE clause, the constraints will be joined with AND.

A query language is really nothing without the ability for OR queries (or sub-queries). Just like in MongoDB, the $or construct can be used. The usage is simple: you give the query hash-ref a key called $or, with a value which is an array reference. This array reference holds one or more (well, two or more if you actually want it to mean anything) hash-refs of constraints. For example:

        $query = {
                imdb_score => { '$gt' => 7 },
                '$or' => [
                        { title => 'Freaks and Geeks' },
                        { title => 'Undeclared' },
                ],
        }

If we were to translate this to an SQL WHERE clause, this is what we'd get:

        WHERE imdb_score > 7 AND (title = 'Freaks and Geeks' OR title = 'Undeclared')

So, in order to match this query, a document needs to have the 'imdb_score' attribute with a value larger than 7, and a 'title' attribute with either 'Freaks and Geeks' or 'Undeclared' as its value.

You might notice we've already done pretty much the same thing with the $in constraint. But the $in constraint is very simple, while $or can be used for more complex constraints, such as this:

        $query = {
                '$or' => [
                        { imdb_score => { '$gte' => 4, '$lte' => 7 } },
                        { year => { '$gte' => 2000, '$lt' => DateTime->now->year } },
                        { comments => { '$type' => 'array', '$size' => 100 } },
                ],
        }

DYNAMICALLY CALCULATED ATTRIBUTES

Since version 0.004, MQUL can dynamically calculate "fake attributes", such as the minimum of a list of attributes, and query on these as if they were true attributes of the document.

For example, consider the following document:

        $document = {
                one => 1,
                two => 2,
                three => 3
        }

The min() and max() "functions" can be used to query on the minimum and maximum of these attributes, respectively:

        $query = { min(one, two, three) => 1 }  # true
        $query = { max(one, two, three) => 3 }  # true
        $query = { min(one, two, three) => 2 }  # false

Apart from min() and max(), the abs() function can be used to query on the absolute value of an attribute. For example:

        $document = {
                some_number => -4.3,
                other_number => 0
        }

        $query = { abs(some_number) => { '$gt' => 0 } }         # true
        $query = { abs(some_number) => -4.3 }                   # false

UPDATE STRUCTURES ^

Update structures are used to modify the attributes of documents. The keys of an update structure are modifiers, and their values are hash-references. These hash-refs have one or more attributes (of the document) as keys, and the actual modifications as the values.

Let's look at a simple example:

        $update = { '$inc' => { number => 3 } }

This update structure uses the $inc update modifier, and it tells MQUL to increase the value of the 'number' attribute by three.

The following update modifiers are supported:

NOTABLE DIFFERENCES FROM MONGODB ^

QUERIES

1. The $nor constraint is not supported (yet).
2. The $elemMatch construct is not supported (yet).
3. The $not meta operator is not supported (yet).
4. The $where construct is not supported (and probably never will be).
5. The direct equality constraint can also compare complex data structures in MQUL. See "THE EQUALITY CONSTRAINT".
6. The dot notation, for querying sub-attributes, is not supported (yet).
7. The $type operator is very different in MQUL. See "THE TYPE CONSTRAINT".

UPDATES

1. The $bit modifier is not supported (yet).
2. The $ positional operator is not supported (and I don't think it will be).
3. The dot notation, for updating sub-attributes, is not supported (yet).

AUTHOR ^

Ido Perlmuter <ido at ido50 dot net>

LICENSE AND COPYRIGHT ^

Copyright (c) 2011-2013, Ido Perlmuter ido at ido50 dot net.

This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either version 5.8.1 or any later version. See perlartistic and perlgpl.

The full text of the license can be found in the LICENSE file included with this module.

DISCLAIMER OF WARRANTY ^

BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR CORRECTION.

IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

syntax highlighting: