mongo $ slice查询反向索引超出范围

时间:2014-10-05 13:55:29

标签: mongodb mongodb-query aggregation-framework

mongo中的以下查询表现得很奇怪:

db.items.findOne({},{ "List": { "$slice": [ skip, 3 ] }})

第一:

,它不是仅使用[“_id”,“List”]键返回一个对象,而是返回一个完整的对象。

第二: 如果skip为负且|skip|高于list.length,则返回前三个元素,就像skip==0

一样

我希望:

{
       "_id" : ObjectId("542babf265f5de9a0d5c2928"),
       "List" : [
                1,
                2,
                3,
                4,
                5
        ]
        "other" : "not_important"
}

查询:

db.items.findOne({},{ "List": { "$slice": [-10, 3 ] }})

得到:

{
       "_id" : ObjectId("542babf265f5de9a0d5c2928"),
       "List" : []
}

相反,我得到:

{
       "_id" : ObjectId("542babf265f5de9a0d5c2928"),
       "List" : [
                1,
                2,
                3
        ]
        "other" : "not_important"
}

为什么?

我使用mongoDB 2.4.10

2 个答案:

答案 0 :(得分:4)

  

第二:如果skip为负且| skip |高于list.length然后返回前三个元素,就像skip == 0

一样

是。这就是javascript Array.prototype.slice()方法的工作原理,mongodb在内部使用它。

根据ECMAScript® Language Specification

  

如果relativeStart为负数,则k为max((len + relativeStart),0);   否则让k为min(relativeStart,len)。

在您的案例中relativeStart is -10k = max((-10+5),0), k = 0;(其中,5是数组的长度)。

因此,在这些情况下,kskip始终为0

  

首先:它不是仅使用[" _id"," List"]键返回一个对象,而是返回一个完整的对象。

是的,投影操作员以这种方式工作。除非在投影参数中明确指定inclusionexclusion,否则将使用投放操作符检索整个文档,例如$slice$elemmatch

db.items.findOne({},{"_id":1,"List": { "$slice": [-10, 3 ] }})

将返回:

{ "_id" : ObjectId("542babf265f5de9a0d5c2928"), "List" : [ 1, 2, 3 ] }

findOne()方法的第二个参数是not only for simple projection目的,字段投影,仅当field个名称中的任何一个具有值01反对他们。如果不是,则返回整个文档。如果任何字段要应用projection operator,则为appliedprojected

当涉及$slice运算符时,投影机制似乎以下面的方式发生。

  • 默认情况下,所有字段都会包含在投影中。
  • 默认情况下,无论以下情况如何,都会始终显示其值基于投影运算符$slice if truthy 得出的所有字段。

排除或包含的步骤。

  • 投影参数中指定的字段列表按指定顺序累计。
  • 仅针对值' 0'遇到的第一个字段或' 1' : 如果 字段值为' 0' 0 - 然后它被排除,剩下的全部 字段标记为包含在内。 如果某个字段有' 1' - 然后它包括在内,以及所有剩余的字段 被标记为被排除在外。
  • 对于所有后续字段,它们将被排除或包含在内 他们的价值观。

答案 1 :(得分:1)

虽然这种行为是设计用于$slice运算符,但是由于MongoDB 3.2可以对此进行评估并使用$slice的聚合运算符更改结果:

给出示例文档:

Object.extend = function (source, extension) {
    var hasOwnProperty = Object.hasOwnProperty;
    var object = Object.create(source);
 
    for (var property in extension)
        if (hasOwnProperty.call(extension, property) ||
            typeof object[property] === "undefined")
                object[property] = extension[property];

    return object;
};

var rectangle = {
    create: function (width, height) {
        var self = {
            width: width,
            height: height,
            area: function () {
                return self.width * self.height;
            }
        };
        return self;
    }
};

var square = Object.extend(rectangle, {
    create: function (side) {
        return rectangle.create(side, side);
    }
});

var sq = square.create(5);

console.log(sq.area());

如果给出条件表达式来测试具有$size的数组的长度,并且只在反向索引大于或等于该长度时执行$slice,否则返回一个空数组:

{ "_id" : ObjectId("5922846dbcf60428d0f69f6e"), "a" : [ 1, 2, 3, 4 ] }
{ "_id" : ObjectId("5922847cbcf60428d0f69f6f"), "a" : [ 5, 6 ] }

然后你得到:

db.collection.aggregate([
  { "$project": {
    "a": {
      "$cond": {
        "if": { "$gte": [ { "$size": "$a" }, 4 ] },
        "then": { "$slice": [ "$a", -4, 2 ] },
        "else": { "$literal": [] },
      }
    }
  }}
])

这就是为什么你可以让MongoDB返回一个以这种方式起作用的“切片”。