mongodb在查找查询中获取_id作为字符串
Posted
技术标签:
【中文标题】mongodb在查找查询中获取_id作为字符串【英文标题】:mongodb get _id as string in find query 【发布时间】:2016-01-23 07:13:39 【问题描述】:在这里我创建了一个包含单个文档的集合
db.getCollection('example').insert("example":1);
我尝试过使用 Projection,但我找回了 _id。
db.getCollection('example').find("example":1,"_id":1);
"_id" : ObjectId("562a6300bbc948a4315f3abc")
但是,我需要如下所示的输出。
-
id 而不是 _id
ObjectId("562a6300bbc948a4315f3abc") 与 "562a6300bbc948a4315f3abc"
"id" : "562a6300bbc948a4315f3abc"
虽然我可以在我的应用服务器(基于 php)上处理 #1 和 #2 以获得所需的输出,但我正在寻找是否有一种方法可以在从 mongo 本身查询时获得预期结果
【问题讨论】:
【参考方案1】:您需要使用.aggregate()
方法。
db.getCollection('example').aggregate([ "$project": "_id": 0, "id": "$_id" ]);
产量:
"id" : ObjectId("562a67745488a8d831ce2e35")
或使用.str
属性。
db.getCollection('example').find("example":1,"_id":1).map(function(doc)
return 'id': doc._id.str
)
返回:
[ "id" : "562a67745488a8d831ce2e35" ]
如果您使用的是 PHP 驱动程序,您可以执行以下操作:
$connection = new MongoClient();
$db = $connection->test;
$col = $db->example;
$cursor = $col->find([], ["_id" => 1]);
foreach($cursor as $doc) print_r(array("id" => $doc["_id"]));
产量:
Array
(
[id] => MongoId Object
(
[$id] => 562a6c60f850734c0c8b4567
)
)
或者再次使用MongoCollection::aggregate
方法。
$result = $col->aggregate(array(["$project" => ["id" => "$_id", "_id" => 0]]))
然后使用foreach
循环:
Array
(
[_id] => MongoId Object
(
[$id] => 562a6c60f850734c0c8b4567
)
)
【讨论】:
谢谢。我不确定 PHP mongo 驱动程序是否支持 cursor.map。有什么想法吗? 在我的问题中提到,在获得光标句柄后,我能够在 PHP 上处理 1&2。但是我的问题是从 mongo 本身检索 [ "id" : "562a67745488a8d831ce2e35" ] :) 让我们continue this discussion in chat.【参考方案2】:在 PHP 端遍历 MongoCursor 的一个简单解决方案是使用生成器以及 foreach
或 array_map($function, iterator_to_array($cursor))
。
示例:
function map_traversable(callable $mapper, \Traversable $iterator)
foreach($iterator as $val)
yield $mapper($val);
您可以在PHP documentation about generators syntax 认识更多。
因此,现在您可以使用/重用它(或类似的实现)以任何数量的映射(就像管道在 aggregate
中所做的那样)在 PHP 端“投影”您的数据的任何建议,但迭代量更少。在重用 map
函数的情况下,这个解决方案对于 OOP 来说非常方便。
更新: 仅针对您的案例示例:
$cursor = $db->getCollection('example')->find(["example":1],["_id":1]);
$mapper = function($record)
return array('id' => (string) $record['_id']); //see \MongoId::__toString()
$traversableWithIdAsStringApplied = map_traversable($mapper, $cursor);
//...
现在您可以继续对 $traversableWithIdAsStringApplied 应用更多映射,或者仅使用 iterator_to_array 进行简单的数组检索。
【讨论】:
【参考方案3】:MongoDB 4.0 添加了 $convert
聚合运算符和 $toString
别名,这使您可以做到这一点:
db.getCollection('example').aggregate([
"$match": "example":1 ,
"$project": "_id": "$toString": "$_id"
])
一个主要的用法很可能是使用_id
值作为文档中的“键”。
db.getCollection('example').insertOne( "a": 1, "b": 2 )
db.getCollection('example').aggregate([
"$replaceRoot":
"newRoot":
"$arrayToObject": [
[
"k": "$toString": "$_id" ,
"v":
"$arrayToObject":
"$filter":
"input": "$objectToArray": "$$ROOT" ,
"cond": "$ne": ["$$this.k", "_id"]
]
]
])
哪个会返回:
"5b06973e7f859c325db150fd" : "a" : 1, "b" : 2
与其他示例一样,清楚地显示了字符串。
虽然通常有一种方法可以在从服务器返回文档时对光标进行“转换”。这通常是一件好事,因为 ObjectId
是 12 字节的二进制表示,而不是占用更多空间的 24 个字符的十六进制“字符串”。
shell 有一个.map()
方法
db.getCollection('example').find().map(d => Object.assign(d, _id: d._id.valueOf() ) )
NodeJS 有一个 Cursor.map()
可以做很多相同的事情:
let cursor = db.collection('example').find()
.map(( _id, ...d ) => ( _id: _id.toString(), ...d ));
while ( await cursor.hasNext() )
let doc = cursor.next();
// do something
)
同样的方法也存在于其他驱动程序中(只是不是 PHP),或者您可以迭代光标并转换内容,这可能是最好的做法。
事实上,当在 shell 中工作时,通过简单地添加到任何游标返回语句中,整个游标结果可以很容易地简化为单个对象
.toArray().reduce((o,e) =>
var _id = e._id;
delete e._id;
return Object.assign(o, [_id]: e )
, )
或者对于完整的 ES6 javascript 支持环境,例如 nodejs:
.toArray().reduce((o,( _id, ...e )) => ( ...o, [_id]: e ), )
真正简单的东西,没有聚合框架中需要处理的复杂性。并且非常可能通过几乎相同的方式使用任何语言。
【讨论】:
以上是关于mongodb在查找查询中获取_id作为字符串的主要内容,如果未能解决你的问题,请参考以下文章