MongoDB $包含NaN值

时间:2014-09-02 04:22:40

标签: javascript mongodb mongodb-query

我必须处理MongoDB集合中的不一致文档,其中某些字段可能是数字或可能具有NaN值。我需要用$ inc更新它。但看起来如果它有NaN值$ inc没有效果。可用于原子文档更新的选项是什么?

1 个答案:

答案 0 :(得分:3)

这似乎导致了两个合乎逻辑的结论。首先,如果字段中存在NaN值,那么如何识别它们?考虑以下示例,让我们调用集合“nantest”

{ "_id" : ObjectId("54055993b145d1c015a1ad41"), "n" : NaN }
{ "_id" : ObjectId("540559e8b145d1c015a1ad42"), "n" : Infinity }
{ "_id" : ObjectId("54055b59b145d1c015a1ad43"), "n" : 1 }
{ "_id" : ObjectId("54055ea1b145d1c015a1ad44"), "n" : -Infinity }

因此,NaNInfinity-Infinity都代表了您的数据中出现的“非数字”。查找以这种方式设置该字段的文档的最佳方法是使用$where运算符来获取JavaScript评估的查询条件。没有效率,但你得到的是:

db.nantest.find({ 
    "$where": "return isNaN(this.n) || Math.abs(this.n) == Infinity" 
})

因此,这提供了一种查找问题数据的方法。从这里你可以跳过箍并决定在遇到这种情况时你只需要在递增之前将其重置为0,基本上发出两个更新语句,其中第一个不匹配文档要更新如果值正确:

db.nantest.update(
    { "$where": "return isNaN(this.n) || Math.abs(this.n) == Infinity" },
    { "$set": { "n": 0 } }
);
db.nantest.update(
    { },
    { "$inc": { "n": 1 } }
);

但实际上,当你看到它时,为什么要修补你的代码以便在你可以修补数据时满足这个要求。因此,最后得出结论的逻辑是将所有Nan和可能的Infinity值更新为一个语句中的标准重置号:

db.nantest.update(
    { "$where": "return isNaN(this.n) || Math.abs(this.n) == Infinity" },
    { "$set": { "n": 0 } },
    { "multi": true }
);

运行一个语句,然后您不必更改代码,只需按照通常的预期处理增量。

如果您的问题是知道哪些字段具有Nan值以便调用更新来修复它们,那么请考虑使用此mapReduce进程来检查字段:

db.nantest.mapReduce(
  function () {

    var doc = this;
    delete doc._id;

    Object.keys( doc ).forEach(function(key) {
      if ( isNaN( doc[key] ) || Math.abs(doc[key]) == Infinity )
        emit( key, 1 );
    });

  },
  function (key,values) {
    return Array.sum( values );
  },
  { "out": { "inline": 1 } }
)

您可能需要为更多嵌套文档添加一些复杂性,但这会告诉您哪些字段可能包含错误值,因此您可以构造更新语句来修复它们。

看起来似乎不是为了适应这种情况而弯曲代码,而是“应该”这样做:

  1. 找到导致数字出现的来源并修复该数据。

  2. 标识包含这些值的字段

  3. 处理一次关闭更新语句以一次性修复所有数据。

  4. 最小化您的代码,它既修复了问题的“来源”,又修复了引入的数据损坏的“结果”。