这里我创建了一个包含单个文档的集合
db.getCollection('example').insert({"example":1});
我试过使用Projection,然后我找回_id。
db.getCollection('example').find({"example":1},{"_id":1});
{
"_id" : ObjectId("562a6300bbc948a4315f3abc")
}
但是,我需要如下所示的输出。
ObjectId(“562a6300bbc948a4315f3abc”)vs“562a6300bbc948a4315f3abc”
{
"id" : "562a6300bbc948a4315f3abc"
}
虽然我可以在我的应用服务器(基于PHP)上处理#1和#2以获得所需的输出,但我正在寻找是否有办法从mongo本身获得预期的结果
答案 0 :(得分:3)
MongoDB 4.0添加了How to fill a form with post request and get response聚合运算符和$convert
别名,允许您完全执行此操作:
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 }),{ })
非常简单的东西,没有在聚合框架中需要处理的复杂性。并且很可能在任何语言中使用相同的方法。
答案 1 :(得分:2)
您需要使用.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
)
)
答案 2 :(得分:1)
在PHP端遍历MongoCursor的一个简单解决方案是使用生成器以及foreach
或array_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处结识更多。
所以,现在你可以使用/重用它(或类似的实现)来提出任何"投射"您在PHP端的数据与任何数量的映射(就像aggregate
中的管道一样)但迭代次数较少。在重用map
函数的情况下,此解决方案对于OOP非常方便。
UPD: 仅为您的案例示例:
$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进行简单的数组检索。