从嵌入式文档中获取价值 Mongo Java
Get value from Embedded Document Mongo Java
我在 mongo 中有以下文档:
> { "_id": ObjectId("569afce4b932c542500143ec"),
> "date": "2016-1-17T2:31:0Z",
> "day": NumberInt(17),
> "model1": {
> "date": "2016-01-17T02:31+0000",
> "MondayModel": {
> "gtxdotdot": {
> "xdotdot": 0,
> "xdot": 0
> },
> "lsxdotdot": {
> "xdotdot": 0,
> "xdot": 0
> },
> "gtxdot": {
> "xdotdot": 0,
> "xdot": 0
> },
> "lsxdot": {
> "xdotdot": 0,
> "xdot": 0
> },
> "modeldotdot": {
> "mean": 0,
> "sdvar": 0
> },
> "modeldot": {
> "mean": 0,
> "sdvar": 0
> }
> }
> }
我希望既能找到该文档又能仅提取 model1.MondayModel.gtxdotdot.xdotdot/xdot/mean/sdvar
的值 ...
我当前的代码使用以下代码:
MongoCursor<Document> back = collection.find(and(eq("topic",topic),eq("sp",sp))).limit(1).iterator();
if (back.hasNext())
{
Document doc = back.next();
Document tmpddc1 = (Document)doc.get("model1");
Document tmpddc2 = (Document)tmpddc1.get("MondayModel");
Document tmpddc3 = (Document)tmpddc2.get("gtxdotdot");
gtxdotdotXdotdot = tmpddc3.getDouble("xdotdot");
gtxdotdotXdot = tmpddc3.getDouble("xdot");
tmpddc3 = (Document)tmpddc2.get("lsxdotdot");
lsxdotdotXdotdot = tmpddc3.getDouble("xdotdot");
lsxdotdotXdot = tmpddc3.getDouble("xdot");
tmpddc3 = (Document)tmpddc2.get("gtxdot");
gtxdotXdotdot = tmpddc3.getDouble("xdotdot");
gtxdotXdot = tmpddc3.getDouble("xdot");
tmpddc3 = (Document)tmpddc2.get("lsxdot");
lsxdotXdotdot = tmpddc3.getDouble("xdotdot");
lsxdotXdot = tmpddc3.getDouble("xdot");
tmpddc3 = (Document)tmpddc2.get("modeldotdot");
modeldotdotXmean = tmpddc3.getDouble("mean");
modeldotdotXsdvar = tmpddc3.getDouble("sdvar");
tmpddc3 = (Document)tmpddc2.get("modeldot");
modeldotXmean = tmpddc3.getDouble("mean");
modeldotXsdvar = tmpddc3.getDouble("sdvar");
}
而不是 运行 认为他的文档(如上所述)有没有办法使用点符号 [model1.MondayModel.gtxdotdot.xdotdot]
来获取值?例如:
double value = doc.getDouble("model1.MondayModel.gtxdotdot.xdotdot");
我认为您不能直接使用点表示法,但可以创建自己的辅助函数。
解决方案 1:使用点符号获取字段
public static Object getWithDotNotation( Document document, String dots )
throws MongoException{
String[] keys = dots.split( "\." );
Document doc = document;
for( int i = 0; i < keys.length - 1; i++ ){
Object o = doc.get( keys[ i ] );
if( o == null || !( o instanceof Document ) ){
throw new MongoException( String.format(
"Field '%s' does not exist or s not a Document", keys[ i ] ) );
}
doc = ( Document ) o;
}//end for
return doc.get( keys[ keys.length - 1 ] );
}
然后您可以像这样使用它:
String dotNotation = "model1.MondayModel.gtxdotdot.xdotdot";
FindIterable<Document> projection = mongoColl.find()
.projection( fields( include( dotNotation ) ) );
Double value = ( Double ) getWithDotNotation( projection.first(), dotNotation );
System.out.println( value ); // result: 0.0
这将大大简化您的代码。唯一需要注意的是:
- 如果您不确定自己的点符号,请使用
try catch
块
- 方法
getWithDotNotation
可能 return 无效
- 小心强制转换,仅当您 100% 确定数据类型(此处为 Double)时才使用它。
解决方案 2:扁平化文档
public static Document flattenDoc( Document document ){
Document flattened = new Document();
Queue<Pair<String, Document>> queue = new ArrayDeque<>();
queue.add( new Pair<>( "", document ) );
while( !queue.isEmpty() ){
Pair<String, Document> pair = queue.poll();
String key = pair.getKey();
for( Map.Entry<String, Object> entry : pair.getValue().entrySet() ){
if( entry.getValue() instanceof Document ){
queue.add( new Pair<>( key + entry.getKey() + ".", ( Document ) entry.getValue() ) );
}else{
flattened.put( key + entry.getKey(), entry.getValue() );
}
}//end for
}
return flattened;
}
根据您的示例数据,flattenDoc
的结果如下:
Document{{_id=569afce4b932c542500143ec,
date=2016-1-17T2:31:0Z,
day=17,
model1.date=2016-01-17T02:31+0000,
model1.MondayModel.gtxdotdot.xdotdot=0.0,
model1.MondayModel.gtxdotdot.xdot=0.0,
model1.MondayModel.lsxdotdot.xdotdot=0.0,
model1.MondayModel.lsxdotdot.xdot=0.0,
model1.MondayModel.gtxdot.xdotdot=0.0,
model1.MondayModel.gtxdot.xdot=0.0,
model1.MondayModel.lsxdot.xdotdot=0.0,
model1.MondayModel.lsxdot.xdot=0.0,
model1.MondayModel.modeldotdot.mean=0.0,
model1.MondayModel.modeldotdot.sdvar=0.0,
model1.MondayModel.modeldot.mean=0.0,
model1.MondayModel.modeldot.sdvar=0.0}}
所以可以直接使用getDouble("model1.MondayModel.gtxdotdot.xdotdot")
。如果您需要访问所有字段,此方法可能更有效。
您可以选择以下三种方式之一。
您可以使用聚合框架来投影使用点表示法的嵌入字段的值。
使用聚合
import static com.mongodb.client.model.Aggregates.*;
import static com.mongodb.client.model.Filters.eq;
import static com.mongodb.client.model.Projections.computed;
import static java.util.Arrays.*;
import static com.mongodb.client.model.Projections.include;
MongoClient mc = new MongoClient();
MongoDatabase db = mc.getDatabase("test");
MongoCollection<Document> collection = db.getCollection("collection");
Document document =
collection.aggregate(asList(
match(eq("day",17)),
project(computed("val", "$model1.MondayModel.gtxdotdot.xdotdot")))).
first();
Double embeddedField = document.getDouble("val");
使用不同
Double embeddedField = collection.distinct("model1.MondayModel.gtxdotdot.xdotdot", eq("day",17), Double.class).first();
使用查找
Document document = collection.find(eq("day",17)).projection(include("model1.MondayModel.gtxdotdot.xdotdot")).first();
Double embeddedField = document.get("model1", Document.class).get("MondayModel", Document.class).get("gtxdotdot", Document.class).getDouble("xdotdot")
在 MongoDB 和 Java 的更新版本中,您可以在 Document
上使用 getEmbedded()
方法,其中 path
是您的字符串路径到内含价值。下面的 shorthand 和上面的完全一样。对于那些只在少数地方需要它并且不想编写整个函数的人很有用。
String path = "model1.MondayModel.gtxdotdot.xdotdot";
Double value = document.getEmbedded(Arrays.stream(path.split("\.")).toList(), Double.class);
我不确定这种方法的效率,但它肯定是更少的代码。
我在 mongo 中有以下文档:
> { "_id": ObjectId("569afce4b932c542500143ec"),
> "date": "2016-1-17T2:31:0Z",
> "day": NumberInt(17),
> "model1": {
> "date": "2016-01-17T02:31+0000",
> "MondayModel": {
> "gtxdotdot": {
> "xdotdot": 0,
> "xdot": 0
> },
> "lsxdotdot": {
> "xdotdot": 0,
> "xdot": 0
> },
> "gtxdot": {
> "xdotdot": 0,
> "xdot": 0
> },
> "lsxdot": {
> "xdotdot": 0,
> "xdot": 0
> },
> "modeldotdot": {
> "mean": 0,
> "sdvar": 0
> },
> "modeldot": {
> "mean": 0,
> "sdvar": 0
> }
> }
> }
我希望既能找到该文档又能仅提取 model1.MondayModel.gtxdotdot.xdotdot/xdot/mean/sdvar
的值 ...
我当前的代码使用以下代码:
MongoCursor<Document> back = collection.find(and(eq("topic",topic),eq("sp",sp))).limit(1).iterator();
if (back.hasNext())
{
Document doc = back.next();
Document tmpddc1 = (Document)doc.get("model1");
Document tmpddc2 = (Document)tmpddc1.get("MondayModel");
Document tmpddc3 = (Document)tmpddc2.get("gtxdotdot");
gtxdotdotXdotdot = tmpddc3.getDouble("xdotdot");
gtxdotdotXdot = tmpddc3.getDouble("xdot");
tmpddc3 = (Document)tmpddc2.get("lsxdotdot");
lsxdotdotXdotdot = tmpddc3.getDouble("xdotdot");
lsxdotdotXdot = tmpddc3.getDouble("xdot");
tmpddc3 = (Document)tmpddc2.get("gtxdot");
gtxdotXdotdot = tmpddc3.getDouble("xdotdot");
gtxdotXdot = tmpddc3.getDouble("xdot");
tmpddc3 = (Document)tmpddc2.get("lsxdot");
lsxdotXdotdot = tmpddc3.getDouble("xdotdot");
lsxdotXdot = tmpddc3.getDouble("xdot");
tmpddc3 = (Document)tmpddc2.get("modeldotdot");
modeldotdotXmean = tmpddc3.getDouble("mean");
modeldotdotXsdvar = tmpddc3.getDouble("sdvar");
tmpddc3 = (Document)tmpddc2.get("modeldot");
modeldotXmean = tmpddc3.getDouble("mean");
modeldotXsdvar = tmpddc3.getDouble("sdvar");
}
而不是 运行 认为他的文档(如上所述)有没有办法使用点符号 [model1.MondayModel.gtxdotdot.xdotdot]
来获取值?例如:
double value = doc.getDouble("model1.MondayModel.gtxdotdot.xdotdot");
我认为您不能直接使用点表示法,但可以创建自己的辅助函数。
解决方案 1:使用点符号获取字段
public static Object getWithDotNotation( Document document, String dots )
throws MongoException{
String[] keys = dots.split( "\." );
Document doc = document;
for( int i = 0; i < keys.length - 1; i++ ){
Object o = doc.get( keys[ i ] );
if( o == null || !( o instanceof Document ) ){
throw new MongoException( String.format(
"Field '%s' does not exist or s not a Document", keys[ i ] ) );
}
doc = ( Document ) o;
}//end for
return doc.get( keys[ keys.length - 1 ] );
}
然后您可以像这样使用它:
String dotNotation = "model1.MondayModel.gtxdotdot.xdotdot";
FindIterable<Document> projection = mongoColl.find()
.projection( fields( include( dotNotation ) ) );
Double value = ( Double ) getWithDotNotation( projection.first(), dotNotation );
System.out.println( value ); // result: 0.0
这将大大简化您的代码。唯一需要注意的是:
- 如果您不确定自己的点符号,请使用
try catch
块 - 方法
getWithDotNotation
可能 return 无效 - 小心强制转换,仅当您 100% 确定数据类型(此处为 Double)时才使用它。
解决方案 2:扁平化文档
public static Document flattenDoc( Document document ){
Document flattened = new Document();
Queue<Pair<String, Document>> queue = new ArrayDeque<>();
queue.add( new Pair<>( "", document ) );
while( !queue.isEmpty() ){
Pair<String, Document> pair = queue.poll();
String key = pair.getKey();
for( Map.Entry<String, Object> entry : pair.getValue().entrySet() ){
if( entry.getValue() instanceof Document ){
queue.add( new Pair<>( key + entry.getKey() + ".", ( Document ) entry.getValue() ) );
}else{
flattened.put( key + entry.getKey(), entry.getValue() );
}
}//end for
}
return flattened;
}
根据您的示例数据,flattenDoc
的结果如下:
Document{{_id=569afce4b932c542500143ec,
date=2016-1-17T2:31:0Z,
day=17,
model1.date=2016-01-17T02:31+0000,
model1.MondayModel.gtxdotdot.xdotdot=0.0,
model1.MondayModel.gtxdotdot.xdot=0.0,
model1.MondayModel.lsxdotdot.xdotdot=0.0,
model1.MondayModel.lsxdotdot.xdot=0.0,
model1.MondayModel.gtxdot.xdotdot=0.0,
model1.MondayModel.gtxdot.xdot=0.0,
model1.MondayModel.lsxdot.xdotdot=0.0,
model1.MondayModel.lsxdot.xdot=0.0,
model1.MondayModel.modeldotdot.mean=0.0,
model1.MondayModel.modeldotdot.sdvar=0.0,
model1.MondayModel.modeldot.mean=0.0,
model1.MondayModel.modeldot.sdvar=0.0}}
所以可以直接使用getDouble("model1.MondayModel.gtxdotdot.xdotdot")
。如果您需要访问所有字段,此方法可能更有效。
您可以选择以下三种方式之一。
您可以使用聚合框架来投影使用点表示法的嵌入字段的值。
使用聚合
import static com.mongodb.client.model.Aggregates.*;
import static com.mongodb.client.model.Filters.eq;
import static com.mongodb.client.model.Projections.computed;
import static java.util.Arrays.*;
import static com.mongodb.client.model.Projections.include;
MongoClient mc = new MongoClient();
MongoDatabase db = mc.getDatabase("test");
MongoCollection<Document> collection = db.getCollection("collection");
Document document =
collection.aggregate(asList(
match(eq("day",17)),
project(computed("val", "$model1.MondayModel.gtxdotdot.xdotdot")))).
first();
Double embeddedField = document.getDouble("val");
使用不同
Double embeddedField = collection.distinct("model1.MondayModel.gtxdotdot.xdotdot", eq("day",17), Double.class).first();
使用查找
Document document = collection.find(eq("day",17)).projection(include("model1.MondayModel.gtxdotdot.xdotdot")).first();
Double embeddedField = document.get("model1", Document.class).get("MondayModel", Document.class).get("gtxdotdot", Document.class).getDouble("xdotdot")
在 MongoDB 和 Java 的更新版本中,您可以在 Document
上使用 getEmbedded()
方法,其中 path
是您的字符串路径到内含价值。下面的 shorthand 和上面的完全一样。对于那些只在少数地方需要它并且不想编写整个函数的人很有用。
String path = "model1.MondayModel.gtxdotdot.xdotdot";
Double value = document.getEmbedded(Arrays.stream(path.split("\.")).toList(), Double.class);
我不确定这种方法的效率,但它肯定是更少的代码。