MongoDB 投影到 return 个子对象作为列
MongoDB projection to return child objects as columns
我是 MongoDB 的新手,我有一个 mongodb 这样的文档
{
"_id": 1,
"title": "abc123",
"author": {
"last": "zzz",
"first": "aaa",
"address": {
"street": "stvalue",
"city": "NewYork"
}
}
}
我正在使用 MongoDB Java 客户端并尝试将上述文档转换为
{
"_id": 1,
"title": "abc123",
"author_last": "zzz",
"author_first": "aaa",
"author_address_street": "stvalue",
"author_address_city": "New York"
}
是否可以使用 MongoDB Java 客户端使用 MongoDB 查询而不修改 Java 中的结果。
更新
由于无法在 MongoQuery 中转换为所需的格式,我不得不改变主意并添加一些 Java 代码以获得所需的格式。
使用 "client" 或 "driver library" 并不是真正的问题,因为唯一的方法是通过 .aggregate()
and $project
到 "alter the fields"回复。这是您最实用的方法:
db.collection.aggregate([
{ "$project": {
"title": 1,
"author_last": "$author.last",
"author_first": "$author.first",
"author_address_street": "$author.address.street",
"author_address_city": "$author.address.city"
}}
])
很容易翻译成任何语言,但向您展示了基本原理。
非常Java(esque) 然后语法变为(在基本驱动程序中):
BasicDBObject project = new BasicDBObject("$project",
new BasicDBObject( "title", 1 )
.append( "author_last", "$author.last" )
.append( "author_first", "$author.first" )
.append( "author_address_street", "$author.address.street" ),
.append( "author_address_city", "$author.address.city" )
);
collection.aggregate(project);
如果您不能仅以这种方式指定键,那么您在服务器上唯一真正的选择是 mapReduce。与上面的方式大致相同,最好在客户端响应中执行此操作:
db.collection.mapReduce(
function() {
var item = {};
var id = this._id;
delete this._id;
var obj = this;
Object.keys(obj).forEach(function(key) {
if ( typeof(obj[key]) == "object" ) {
Object.keys(obj[key]).forEach(function(subKey) {
if ( typeof(obj[key][subkey] == "object" ) {
Object.keys(obj[key][subKey]).forEach(function(subSub) {
item[key + "_" + subKey + "_" + subSub] = obj[key][subKey][subSub];
});
} else {
item[key + "_" + subKey] = obj[key][subKey];
}
});
} else {
item[key] = obj[key];
}
});
emit( id, item );
},
function() {}, // no reduction required
{ "out": { "inline": 1 } }
)
我认为这是有道理的,但我只是输入它所以可能存在语法问题,但这个想法应该是相关的。根据您的实际数据,您可能还需要更复杂的东西。
要点是,您需要Java脚本执行到"traverse"您在服务器上的文档才能使用此方法。
否则,只需在代码中执行相同操作,因为无论如何您都在迭代游标。
这是一个 Java 实现,它将所有子对象转换为 HashMap
private List<Map<String,String>> mapReduce(AggregationOutput output){
List<Map<String,String>> out = new ArrayList<Map<String, String>>();
for (DBObject result : output.results()) {
Map<String,String> map = ConvertDBObjectToMap(result, "");
out.add(map);
}
return out;
}
private Map<String,String> ConvertDBObjectToMap(DBObject result, String parent)
{
String prefix = parent == "" ? "" : parent + "_";
Map<String,String> out = new HashMap<String, String>();
String[] keys = result.keySet().toArray(new String[result.keySet().size()]);
for(String key : keys)
{
Object obj = result.get(key);
if(obj instanceof BasicDBObject)
{
out.putAll(ConvertDBObjectToMap((BasicDBObject) obj, prefix + key));
}
else if(obj instanceof String)
{
out.put(prefix + key,(String)obj);
}
else if(obj instanceof Date){
out.put(prefix + key,obj.toString());
}
else{
out.put(prefix + key,obj.toString());
}
}
return out;
}
我是 MongoDB 的新手,我有一个 mongodb 这样的文档
{
"_id": 1,
"title": "abc123",
"author": {
"last": "zzz",
"first": "aaa",
"address": {
"street": "stvalue",
"city": "NewYork"
}
}
}
我正在使用 MongoDB Java 客户端并尝试将上述文档转换为
{
"_id": 1,
"title": "abc123",
"author_last": "zzz",
"author_first": "aaa",
"author_address_street": "stvalue",
"author_address_city": "New York"
}
是否可以使用 MongoDB Java 客户端使用 MongoDB 查询而不修改 Java 中的结果。
更新
由于无法在 MongoQuery 中转换为所需的格式,我不得不改变主意并添加一些 Java 代码以获得所需的格式。
使用 "client" 或 "driver library" 并不是真正的问题,因为唯一的方法是通过 .aggregate()
and $project
到 "alter the fields"回复。这是您最实用的方法:
db.collection.aggregate([
{ "$project": {
"title": 1,
"author_last": "$author.last",
"author_first": "$author.first",
"author_address_street": "$author.address.street",
"author_address_city": "$author.address.city"
}}
])
很容易翻译成任何语言,但向您展示了基本原理。
非常Java(esque) 然后语法变为(在基本驱动程序中):
BasicDBObject project = new BasicDBObject("$project",
new BasicDBObject( "title", 1 )
.append( "author_last", "$author.last" )
.append( "author_first", "$author.first" )
.append( "author_address_street", "$author.address.street" ),
.append( "author_address_city", "$author.address.city" )
);
collection.aggregate(project);
如果您不能仅以这种方式指定键,那么您在服务器上唯一真正的选择是 mapReduce。与上面的方式大致相同,最好在客户端响应中执行此操作:
db.collection.mapReduce(
function() {
var item = {};
var id = this._id;
delete this._id;
var obj = this;
Object.keys(obj).forEach(function(key) {
if ( typeof(obj[key]) == "object" ) {
Object.keys(obj[key]).forEach(function(subKey) {
if ( typeof(obj[key][subkey] == "object" ) {
Object.keys(obj[key][subKey]).forEach(function(subSub) {
item[key + "_" + subKey + "_" + subSub] = obj[key][subKey][subSub];
});
} else {
item[key + "_" + subKey] = obj[key][subKey];
}
});
} else {
item[key] = obj[key];
}
});
emit( id, item );
},
function() {}, // no reduction required
{ "out": { "inline": 1 } }
)
我认为这是有道理的,但我只是输入它所以可能存在语法问题,但这个想法应该是相关的。根据您的实际数据,您可能还需要更复杂的东西。
要点是,您需要Java脚本执行到"traverse"您在服务器上的文档才能使用此方法。
否则,只需在代码中执行相同操作,因为无论如何您都在迭代游标。
这是一个 Java 实现,它将所有子对象转换为 HashMap
private List<Map<String,String>> mapReduce(AggregationOutput output){
List<Map<String,String>> out = new ArrayList<Map<String, String>>();
for (DBObject result : output.results()) {
Map<String,String> map = ConvertDBObjectToMap(result, "");
out.add(map);
}
return out;
}
private Map<String,String> ConvertDBObjectToMap(DBObject result, String parent)
{
String prefix = parent == "" ? "" : parent + "_";
Map<String,String> out = new HashMap<String, String>();
String[] keys = result.keySet().toArray(new String[result.keySet().size()]);
for(String key : keys)
{
Object obj = result.get(key);
if(obj instanceof BasicDBObject)
{
out.putAll(ConvertDBObjectToMap((BasicDBObject) obj, prefix + key));
}
else if(obj instanceof String)
{
out.put(prefix + key,(String)obj);
}
else if(obj instanceof Date){
out.put(prefix + key,obj.toString());
}
else{
out.put(prefix + key,obj.toString());
}
}
return out;
}