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

x33g5p2x  于 2023-11-17  发布在  Go
关注(0)|答案(6)|浏览(247)

我正在从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);


它看起来很可怕,但它工作。
我很乐意听到更好的解决方案。

pwuypxnk

pwuypxnk1#

原因是new MongoDB driver处理MongoDB文档到PHP类型的转换不同于the old driver
好消息是,你可以通过指定一个所谓的“类型Map”来获得旧的行为。
文档有点隐藏,但你可以在in the github repository of the driver或在线文档中阅读。
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()之后应该可以。

6yoyoihd

6yoyoihd2#

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类时的输出。为此,您需要调整setting up the MongoDB driver位于'vendor/mongodb/mongodb/src/Model'文件夹中时获得的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();
    }
}

xlpyo6sf

xlpyo6sf3#

使用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在没有显式设置时添加数字索引,因此您可能应该向客户端发送一个数组,而不是再次解码->删除索引->编码->删除索引。
或者在客户端收到索引后删除索引。

ghg1uchk

ghg1uchk4#

是否有从0到n的所有索引或者它们中的任何一个缺失?这可能是原因。如果你想将它转换回数组,你可能会使用

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

字符串
然后

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


去掉索引
我仍然很确定缺少了一些值,但是在你的例子中看不到。

hfwmuf9z

hfwmuf9z5#

mthierer几乎有正确的解决方案。
在示例化客户端时,您需要将typeMap放在驱动程序选项(第三个参数)中。
var driver_options ={'typeMap'=>{'root':'array ',' document':'array',' array':'array']}; var client = new MongoDB\Client(conn,options,driver_options);
这比在每次游标示例化之后都这样做要好。

bvn4nwqk

bvn4nwqk6#

对于任何需要使用Laravel雄辩和聚合的人,您可以将第二个参数$option传递给聚合方法

Collection::raw(function ($collection) {
  $aggregationPipeLine = [];
  return $collection->aggregate($aggregationPipeLine, [
    'typeMap' => [
      'array' => 'array',
      'document' => 'array',
      'root' => 'array'
    ]
  ]);
});

字符串
查看https://www.mongodb.com/docs/php-library/current/reference/method/MongoDBCollection-aggregate/#definition

相关问题