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 的一个简单解决方案是使用生成器以及 foreacharray_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作为字符串的主要内容,如果未能解决你的问题,请参考以下文章

使用 _id 字符串的 GraphQL 查询,对象 ID 存储在 MongoDB 中

MongoDB查询:如何查找嵌套对象中的字符串

使用部分 _id 字符串查找 mongodb 文档

Mongoose / MongoDB _id 作为字符串

Mongodb:项目只从字符串中获取数值

如何在 MongoDB 中找到“$oid”而不是 _id?