MongoDB (php) - 以数组而不是多个属性的形式返回文档属性


MongoDB (php) - return document property as an array instead of multiple properties

我正在从mongodb数据库中读取一个文档,并将其与php一起传递给客户端。

文档包含一个数组属性。问题在于客户端将其作为具有名称为 01 等属性的对象接收,而不是标准数组。

这是原始数据:

{ 
    "_id" : ObjectId("573b47a1f99a8a1f9a6278a5"), 
    "persons" : [
        {
            "name" : "Moshe",
        }, 
        {
            "name" : "E",
        }, ...
    ]
}

根据要求,我附上var_export:

array (
  0 => 
  MongoDB'Model'BSONDocument::__set_state(array(
     '_id' => 
    MongoDB'BSON'ObjectID::__set_state(array(
    )),
     'persons' => 
    MongoDB'Model'BSONArray::__set_state(array(
       0 => 
      MongoDB'Model'BSONDocument::__set_state(array(
         'name' => 'Moshe',
      )),
       1 => 
      MongoDB'Model'BSONDocument::__set_state(array(
         'name' => 'E',
      )),
    )),
  )),
)

var_dump:

array(1) {
  [0]=>
  object(MongoDB'Model'BSONDocument)#40 (1) {
    ["storage":"ArrayObject":private]=>
    array(2) {
      ["_id"]=>
      object(MongoDB'BSON'ObjectID)#11 (1) {
        ["oid"]=>
        string(24) "573b47a1f99a8d1f986278a5"
      }
      ["persons"]=>
      object(MongoDB'Model'BSONArray)#34 (1) {
        ["storage":"ArrayObject":private]=>
        array(2) {
          [0]=>
          object(MongoDB'Model'BSONDocument)#10 (1) {
            ["storage":"ArrayObject":private]=>
            array(1) {
              ["name"]=>
              string(5) "Moshe"
            }
          }
          [1]=>
          object(MongoDB'Model'BSONDocument)#12 (1) {
            ["storage":"ArrayObject":private]=>
            array(1) {
              ["name"]=>
              string(1) "E"
            }
          }
        }
      }
    }
  }
}

这是PHP代码(全部(:

function select(){
    $conn = new MongoDB'Client("mongodb://localhost:27017");
    $db = $conn->mydb;
    $cursor = $db->entries_meta_data->find();
    return current($cursor->toArray());
}

然后,我使用如下json_encode将对象传递给客户端:

echo json_encode(select());

客户端中显示的结果是:

{ 
    "_id" : ObjectId("573b47a1f99a8a1f9a6278a5"), 
    "persons" : {
        "0" : {
            "name" : "Moshe",
        }, 
        "1" : {
            "name" : "E",
        }, ...
    }
}

编辑:尼奥勋爵居然解决了。阅读他的回答后,我将"选择"函数的最后一行更改为以下内容:

return json_decode(json_encode(current($cursor->toArray()),true);

它看起来很可怕,但它有效。

我将非常乐意听到更好的解决方案。

原因是新的MongoDB驱动程序处理MongoDB文档到PHP类型的转换与旧驱动程序不同。

好消息是,您可以通过指定所谓的"类型映射"来获取旧行为。

该文档有点隐藏,但您可以在驱动程序的 github 存储库或在线文档中阅读它。

TL;DR 是你传递一个数组,如

array(
  'array' => 'array',
  'document' => 'array',
  'root' => 'array'
)

作为MongoDB''Client构造函数的第三个参数("driverOptions"(,或者为每个查询单独调用MongoDB''Driver''Cursor::setTypeMap((。

在您的示例中,调用

$cursor->setTypeMap(array(
  'array' => 'array',
  'document' => 'array',
  'root' => 'array'
));

$db->entries_meta_data->find()之后应该可以解决问题。

MongoDB驱动程序提供了一个MongoDB'BSON'toJSON()函数,可以将数据正确地转换为JSON。因为它需要一个字符串作为输入,所以首先需要对文档调用MongoDB'BSON'fromPHP()。由于看起来您只想获取找到的第一个元素,因此您可以使用 findOne() 方法代替 find() ,这使得获取输出变得非常容易:

function select() {
  $conn = new MongoDB'Client("mongodb://localhost:27017");
  $db = $conn->mydb;
  $doc = $db->entries_meta_data->findOne();
  return MongoDB'BSON'toJSON(MongoDB'BSON'fromPHP($doc));
}

如果要输出多个条目,它会变得有点复杂。这里显示了输出数组的一种(诚然是黑客(方法:

function select() {
  $conn = new MongoDB'Client("mongodb://localhost:27017");
  $db = $conn->mydb;
  $cursor = $db->entries_meta_data->find();
  $result = $cursor->toArray();
  foreach($result as $i => $doc) {
    $result[$i] = MongoDB'BSON'toJSON(MongoDB'BSON'fromPHP($doc));
  }
  return '[' . implode($res) . ']';
}

另一种方法是在json_encode()调用时调整 BSONArray 类的输出。为此,您需要调整在设置位于"vendor/mongodb/mongodb/src/Model"文件夹中的MongoDB驱动程序时获得的BSONArray.php文件,并添加JsonSerializable接口和jsonSerialize()方法,使其如下所示:

<?php
...
class BSONArray extends ArrayObject implements 'JsonSerializable,
    Serializable, Unserializable
{
    ...
    /**
     * Serialize the ArrayObject as normal array
     *
     * @return array
     */  
    public function jsonSerialize() {
        return $this->getArrayCopy();
    }
}

使用 json_decode 时,您可以使用可选的 "true" 参数,它将与数组相关联

$obj = json_decode($json, true);
//$obj will be an associative array

http://php.net/manual/en/function.json-decode.php

然后,您可以使用array_shift剥离索引:

$obj = array_shift($obj);

http://php.net/manual/en/function.array-shift.php

JSON 在未显式设置时添加数字索引,因此您可能应该将数组发送到客户端,而不是解码 ->删除索引 -> conconding -> 再次删除索引。

或者只是在客户端收到索引后删除索引。

是否有

从 0 到 n 的所有索引,或者其中是否有任何索引丢失?这可能就是原因。如果要将其转换回数组,则可以使用

$obj = select(); // changed by the new line added

然后

$obj['persons'] = array_values($obj['persons']); 

以摆脱索引。

我仍然很确定缺少一些价值。但它在您的示例中不可见。

mthierer几乎有正确的解决方案。

实例

化客户端时,您需要将 typeMap 放在驱动程序选项(第 3 个参数(中。

var driver_options = {'typeMap'=>['root':'array', 'document':'array', 'array

':'array']};var client = new MongoDB''Client(conn, options, driver_options(;

这比在每次游标实例化后都必须执行此操作要好。