MongoDB(php) - 将文档属性作为数组而不是多个属性返回

时间:2016-05-17 18:05:33

标签: javascript php mongodb

我正在从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",
        }, ...
    }
}

修改 LordNeo实际上解决了它。在阅读完答案后,我将“选择”功能中的最后一行更改为以下内容:

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

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

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

5 个答案:

答案 0 :(得分:3)

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));
}

如果要输出多个条目,则会更复杂一些。这里显示了输出数组的一种(通常是hacky)方法:

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”文件夹中的setting up the MongoDB driver时获得的BSONArray.php文件,并添加JsonSerializable接口和{{1方法,看起来像这样:

jsonSerialize()

答案 1 :(得分:3)

原因是new MongoDB driver处理MongoDB文档到不同于the old driver的PHP类型的转换。

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

文档有点隐藏,但您可以阅读in the github repository of the driverin the online docs

TL; DR是你传递像

这样的数组
array(
  'array' => 'array',
  'document' => 'array',
  'root' => 'array'
)

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

在你的例子中呼叫

$cursor->setTypeMap(array(
  'array' => 'array',
  'document' => 'array',
  'root' => 'array'
));
$db->entries_meta_data->find()之后

应该做的伎俩。

答案 2 :(得分:2)

使用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在未明确设置时添加数字索引,因此您应该将数组发送到客户端而不是解码 - >删除索引 - > enconding - >再次删除索引。

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

答案 3 :(得分:1)

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

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

然后

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

摆脱指数。

我仍然非常确定缺少一些价值。但是从你的例子中看不出来。

答案 4 :(得分:0)

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

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

var driver_options = {'typeMap'=> ['root':'array','document':'array','array':'array']}; var client = new MongoDB \ Client(conn,options,driver_options);

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