我正在从mongodb数据库中读取一个文档,并将其与php一起传递给客户端。
文档包含一个数组属性。问题在于客户端将其作为具有名称为 0
、1
等属性的对象接收,而不是标准数组。
这是原始数据:
{
"_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(;
这比在每次游标实例化后都必须执行此操作要好。