如何更改mongodb数组值的数据类型?

时间:2015-08-12 09:09:07

标签: mongodb types mongodb-query

有以下文件:

{
"_id" : 1.0000000000000000,
"l" : [ 
    114770288670819.0000000000000000, 
    NumberLong(10150097174480584)
]}

如何将“l”数组的第二个元素从NumberLong转换为flating-point(double),例如第一个元素。

3 个答案:

答案 0 :(得分:1)

好像,因为其他回复要么在执行中非常模糊,要么建议写一个新的集合或其他不安全的#34;操作,然后我想你应该遵循的回应是有序的。

当你考虑到所有的考虑因素时,它们并不是一个简单的问题需要解决(尽管其他人已经打了折扣),例如"保持元素的顺序"并且"不可能覆盖对文档的其他更改",这是生产系统中的重要注意事项。

唯一真正的"安全(ish)" 方式,我可以看到这样做,而不会(大多数)吹掉你的整个阵列并且放弃任何"活性" write使用这样的结构(使用Bulk Operations来提高效率):

var bulk = db.collection.initializeOrderedBulkOp(),
    count = 0;

db.collection.find({ "l": { "$type": 18 }}).forEach(function(doc) {

  bulk.find({ "_id": doc._id }).updateOne({
    "$pull": { "l": { "$in": doc.l } }
  });
  count++;

  if ( count % 1000 == 0 ) {
    bulk.execute();
    bulk = db.collection.initializeOrderedBulkOp();
  }

  doc.l.map(function(l,idx) {
    return { "l": parseFloat(l.valueOf()), "idx": idx }
  }).forEach(function(l) {
    bulk.find({ "_id": doc._id }).updateOne({
      "$push": { "l": { "$each": [l.l], "$position": l.idx } }
    });
    count++;

    if ( count % 1000 == 0 ) {
      bulk.execute();
      bulk = db.collection.initializeOrderedBulkOp();
    }
  });

});

if ( count % 1000 != 0 ) 
  bulk.execute();

这意味着"批量"在需要时重写整个集合中的数据,但在单个样本上,结果为:

{ "_id" : 1, "l" : [ 114770288670819, 10150097174480584 ] }

因此,基本原理是,您将在集合中找到与NumberLong(BSON类型中的64位整数)的当前$type匹配的任何文档,并按以下方式处理结果。

  1. 首先使用已存在的元素值从数组中删除所有元素。

  2. 转换所有元素并将它们添加回阵列中与它们相同的位置。

  3. 现在我说" safe(ish)" ,因为这主要是"安全"考虑到您的文档很可能正在更新并且数组中附加了新项目,或者文档中发生了其他更改,这里有一个可能的问题。

    如果您的数组"值"这里不是真正的"独特的"然后就没有真正的方法来拉动"需要更改的项目,并将它们重新插入到最初发生的位置。不在"原子"和"安全"无论如何。

    所以"风险"这个过程如图所示,是"如果"您碰巧将一个与数组中另一个现有元素具有相同值的新数组元素追加到该数组中(并且只有在为文档读取的游标和批量执行之前发生这种情况时),然后运行" risk&# 34;那个新项目完全从数组中删除。

    但是,如果数组中的所有值都是完全"唯一的"对于每个文档,这将完美地工作"并且只需将所有内容转换回已转换类型的位置,而不是其他任何"冒险"缺少其他文档更新或重要操作。

    这不是一个简单的陈述,因为逻辑要求你采取预防措施。但它不能在已经提到的限制范围内失败。它运行在您现在拥有的集合上,而不会产生新的集合。

答案 1 :(得分:0)

  1. 将文档加载到mongo shell中

    var doc = db.collection.find({ _id:1.0000000000000000});

  2. 使用parseFloat函数显式将字段转换为浮点数:

    doc.l[1] = parseFloat(doc.l[1]);

  3. 将文档保存回数据库

    db.collection.save(doc);

答案 2 :(得分:0)

要更新此值,您应该使用编程语言代码或使用java脚本的一些工作。

其他明智地使用aggregation$out一起在新集合中写下文档,如下所示:

db.collectionName.aggregate({
    "$unwind": "$l"
}, {
    "$project": {
        "l1": {
            "$divide": ["$l", 1] // divide by one or multiply by one 
        }
    }
}, {
    "$group": {
        "_id": "$_id"
        , "l": {
            "$push": "$l1"
        }
    }
}, {
    "$out": "newCollectionName" // write data in new collection
})

如果在上面的查询中完成,则删除旧的集合并使用此新集合。