Mongodb 如何根据 document 现有字段创建新的字段?
发布于 9 年前 作者 fiftyk 3996 次浏览 最后一次编辑是 8 年前 来自 问答
{
	x: 120,
	y: 30
}

//转化成
{
  position: {
    type: 'Point',
	coordinates: [120, 30]
  }
}
9 回复

你需要的是一个脚本,将数据库中的doc转化成你需要的格式。鉴于update的空间消耗,建议存在其他的collection中。

@haozxuan 谢谢

我目前用 nodejs 解决了,效率不高

collection.find({}).each(function (err, item) {
	if(item === null) {
	   logger.trace('end');
	}
	collection.update({id: item._id}, {
		$set: {
			position: {
				type: 'Point',
				coordinate: [item.x, item.y]
			}
		}
	}, function (err, data) {
		logger.trace('......');
	})
});

@fiftyk 允许x.y字段的重复吗?还有你find({})这样做的话,数据量打的时候有些不妥。而且上面提到的update空间消耗问题,由于之前insert时候只有xy字段所以预分配空间会比较小,加入新的结构后会因为空间不够另外开辟空间,换句话说会造成磁盘碎片,而且约到后期update会越慢。当然这些都是量大的时候,如果仅仅是开发阶段你的方案还是不错的。

@haozxuan 自己机器上做测试的, 30W+条记录,

> db.collection.dataSize() 
return:
5921135744

像你说的 update 越来越慢

另外我不用 find({}).each 用什么查询所有数据并更新呢,有什么迭代器吗?

小改动 update 时的查询参数由 {id: : item._id} 改为 {_id: : item._id} , 速度暴增! _id 有索引,唉

@fiftyk find({})没有limit,将30W数据全部读取到内存中欠妥哟

@haozxuan 非常不妥,除了 xy这两个字段,还有其他很多字段,非常不妥,还在想办法。

db.collection.find({}).skip(0).limit(1000).toArray(function (err, items) {
	//...
	db.collection.find({}).skip(1000).limit(1000).toArray(function (err, items) {
		//...
		db.collection.find({}).skip(2000).limit(1000).toArray(function (err, items) {
			//...
		}
	}
});

这样如何?

skip 的这些步骤可以打到for loop里,减少重复代码

@fiftyk 建议看下mongodb权威指南,第二版。 上述方案中有两个比较大的问题: 1、重新开一个collection,把新规则的数据放在另外的表中(姑且这么叫吧)。好处:不会由于update导致磁盘碎片或者update后期越来越慢 2、尽量不要使用skip,这个操作符的工作原理是首先查询到所有符合要求的集合,然后舍弃前n页,这样在数据量大的时候会很慢,具体分页方案网上有很多可以借鉴下。

另外如果性质是数据迁移的话,建议写一个nodejs程序让他跑完所有数据。当然,如果是暂存的一个数据状态的话,也可以起一个nodejs 转数据服务让他跑。

回到顶部