Пример #1
0
 def _parse_basic_expression(self, expression):
     if isinstance(expression, six.string_types) and expression.startswith('$'):
         if expression.startswith('$$'):
             return helpers.get_value_by_dot(dict({
                 'ROOT': self._doc_dict,
                 'CURRENT': self._doc_dict,
             }, **self._user_vars), expression[2:])
         return helpers.get_value_by_dot(self._doc_dict, expression[1:], can_generate_array=True)
     return expression
Пример #2
0
 def test__get_value_by_dot_find_key(self):
     """Test get_value_by_dot when key can be found"""
     for doc, key, expected in (
             ({'a': 1}, 'a', 1),
             ({'a': {'b': 1}}, 'a', {'b': 1}),
             ({'a': {'b': 1}}, 'a.b', 1),
             ({'a': [{'b': 1}]}, 'a.0.b', 1)):
         found = get_value_by_dot(doc, key)
         self.assertEqual(found, expected)
Пример #3
0
def _handle_unwind_stage(in_collection, unused_database, options):
    if not isinstance(options, dict):
        options = {'path': options}
    path = options['path']
    if not isinstance(path, six.string_types) or path[0] != '$':
        raise ValueError(
            '$unwind failed: exception: field path references must be prefixed '
            "with a '$' '%s'" % path)
    path = path[1:]
    should_preserve_null_and_empty = options.get('preserveNullAndEmptyArrays')
    include_array_index = options.get('includeArrayIndex')
    unwound_collection = []
    for doc in in_collection:
        try:
            array_value = helpers.get_value_by_dot(doc, path)
        except KeyError:
            if should_preserve_null_and_empty:
                unwound_collection.append(doc)
            continue
        if array_value is None:
            if should_preserve_null_and_empty:
                unwound_collection.append(doc)
            continue
        if array_value == []:
            if should_preserve_null_and_empty:
                new_doc = copy.deepcopy(doc)
                # We just ran a get_value_by_dot so we know the value exists.
                helpers.delete_value_by_dot(new_doc, path)
                unwound_collection.append(new_doc)
            continue
        if isinstance(array_value, list):
            iter_array = enumerate(array_value)
        else:
            iter_array = [(None, array_value)]
        for index, field_item in iter_array:
            new_doc = copy.deepcopy(doc)
            new_doc = helpers.set_value_by_dot(new_doc, path, field_item)
            if include_array_index:
                new_doc = helpers.set_value_by_dot(new_doc,
                                                   include_array_index, index)
            unwound_collection.append(new_doc)

    return unwound_collection
Пример #4
0
def _extend_collection(out_collection, field, expression):
    field_exists = False
    for doc in out_collection:
        if field in doc:
            field_exists = True
            break
    if not field_exists:
        for doc in out_collection:
            if isinstance(expression,
                          six.string_types) and expression.startswith('$'):
                try:
                    doc[field] = helpers.get_value_by_dot(
                        doc, expression.lstrip('$'))
                except KeyError:
                    pass
            else:
                # verify expression has operator as first
                doc[field] = _parse_expression(expression.copy(), doc)
    return out_collection
Пример #5
0
def _handle_lookup_stage(in_collection, database, options):
    for operator in ('let', 'pipeline'):
        if operator in options:
            raise NotImplementedError(
                "Although '%s' is a valid lookup operator for the "
                'aggregation pipeline, it is currently not '
                'implemented in Mongomock.' % operator)
    for operator in ('from', 'localField', 'foreignField', 'as'):
        if operator not in options:
            raise OperationFailure(
                "Must specify '%s' field for a $lookup" % operator)
        if not isinstance(options[operator], six.string_types):
            raise OperationFailure(
                'Arguments to $lookup must be strings')
        if operator in ('as', 'localField', 'foreignField') and \
                options[operator].startswith('$'):
            raise OperationFailure(
                "FieldPath field names may not start with '$'")
        if operator == 'as' and \
                '.' in options[operator]:
            raise NotImplementedError(
                "Although '.' is valid in the 'as' "
                'parameters for the lookup stage of the aggregation '
                'pipeline, it is currently not implemented in Mongomock.')

    foreign_name = options['from']
    local_field = options['localField']
    foreign_field = options['foreignField']
    local_name = options['as']
    foreign_collection = database.get_collection(foreign_name)
    for doc in in_collection:
        try:
            query = helpers.get_value_by_dot(doc, local_field)
        except KeyError:
            query = None
        if isinstance(query, list):
            query = {'$in': query}
        matches = foreign_collection.find({foreign_field: query})
        doc[local_name] = [foreign_doc for foreign_doc in matches]

    return in_collection