java - 使用 Morphia 返回匹配的数组元素
问题描述
我正在寻找一种List of Object
在提供一些conditions
.
例如
A级
@Entity(value = "tbl_A")
public class A {
private String notes;
@Embedded
private List<SampleObject> sampleObject;
....getter and setter ...
}
B类
@Embedded
public class SampleObject {
private boolean read;
private boolean sentByBot;
... getter and setter ...
}
现在,我只想收集SampleObject
确实有sentByBot
参数设置为true
. 我正在使用以下方法:
Query<A> queryForA = datastore.find(A.class);
queryForA.field("sampleObject.sentByBot").equal(false).retrievedFields(true, "sampleObject.sentByBot");
上面的代码给了我完整的列表,objects
其中有sampleObject.sentByBot
真假。
我也尝试过filter
方法,即
queryForA.filter("sampleObject.sentByBot", false).retrievedFields(true, "sampleObject.sentByBot");
但没有运气。有没有办法只获得那些sampleObject.sentByBot
设置为真的字段?
编辑
实现以下代码后,我得到了这个:
数据库映像
代码
AggregationOptions options = AggregationOptions.builder()
.outputMode(AggregationOptions.OutputMode.CURSOR)
.build();
//System.out.println(options.toString());
Projection filterProjection = Projection.projection(
"sampleObjects",
Projection.expression(
"$filter",
new BasicDBObject("input","$sampleObjects")
.append("cond",new BasicDBObject("$eq", Arrays.asList("$$this.sentByBot",true)))
)
);
AggregationPipeline pipeline = datastore.createAggregation(A.class)
.match(datastore.createQuery(A.class).filter("sampleObjects.sentByBot", true))
.project(
Projection.projection("fieldA"),
Projection.projection("fieldB"),
filterProjection
);
Iterator<A> cursor = pipeline.aggregate(A.class, options);
输出
"Command failed with error 28646: '$filter only supports an object as its argument'. The full response is { \"ok\" : 0.0, \"errmsg\" : \"$filter only supports an object as its argument\", \"code\" : 28646 }"
解决方案
如前所述,为了只返回与给定条件匹配的“多个”数组元素,您想要的是$filter
投影中的聚合管道运算符。为了使用 Morphia 发出这样的聚合语句,您需要这样的东西:
Projection filterProjection = projection(
"sampleObjects",
expression(
"$filter",
new BasicDBObject("input","$sampleObjects")
.append("cond",new BasicDBObject("$eq", Arrays.asList("$$this.sentByBot",true)))
)
);
AggregationPipeline pipeline = datastore.createAggregation(A.class)
.match(datastore.createQuery(A.class).filter("sampleObjects.sentByBot", true))
.project(
projection("fieldA"),
projection("fieldB"),
filterProjection
);
哪个向服务器发出管道:
[
{ "$match" : { "sampleObjects.sentByBot" : true } },
{ "$project" : {
"fieldA" : 1,
"fieldB" : 1,
"sampleObjects" : {
"$filter" : {
"input" : "$sampleObjects",
"cond" : { "$eq" : [ "$$this.sentByBot", true ] }
}
}
}}
]
并且只返回匹配文档中也匹配条件的数组元素:
{
"className" : "com.snakier.example.A" ,
"_id" : { "$oid" : "5b0ce52c6a6bfa50084c53aa"} ,
"fieldA" : "something" ,
"fieldB" : "else" ,
"sampleObjects" : [
{ "name" : "one" , "read" : false , "sentByBot" : true} ,
{ "name" : "three" , "read" : true , "sentByBot" : true}
]
}
请注意,您需要expression()
手动构建 in 参数,DBObject()
因为 Morphia 目前不支持此类操作的“构建器”。预计未来的版本将更改为Document
底层 Java 驱动程序中的标准接口已有一段时间了。
作为一个完整的示例清单:
package com.snakier.example;
import com.mongodb.AggregationOptions;
import com.mongodb.BasicDBObject;
import com.mongodb.MongoClient;
import org.bson.types.ObjectId;
import org.mongodb.morphia.Datastore;
import org.mongodb.morphia.Morphia;
import org.mongodb.morphia.aggregation.AggregationPipeline;
import org.mongodb.morphia.aggregation.Projection;
import org.mongodb.morphia.annotations.Embedded;
import org.mongodb.morphia.annotations.Entity;
import org.mongodb.morphia.annotations.Id;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import static org.mongodb.morphia.aggregation.Projection.*;
public class Application {
public static void main(String[] args) {
final Morphia morphia = new Morphia();
morphia.mapPackage("com.snakier.example");
final Datastore datastore = morphia.createDatastore(new MongoClient(),"example");
// Clean example database
datastore.getDB().getCollection("example").drop();
// Create some data
final A first = new A("something","else");
final A second = new A("another","thing");
final SampleObject firstSample = new SampleObject("one", false, true);
final SampleObject secondSample = new SampleObject("two", false, false);
final SampleObject thirdSample = new SampleObject("three", true,true);
final SampleObject fourthSample = new SampleObject("four", true, false);
first.setSampleObjects(Arrays.asList(firstSample,secondSample,thirdSample));
datastore.save(first);
second.setSampleObjects(Arrays.asList(fourthSample));
datastore.save(second);
AggregationOptions options = AggregationOptions.builder()
.outputMode(AggregationOptions.OutputMode.CURSOR)
.build();
//System.out.println(options.toString());
Projection filterProjection = projection(
"sampleObjects",
expression(
"$filter",
new BasicDBObject("input","$sampleObjects")
.append("cond",new BasicDBObject("$eq", Arrays.asList("$$this.sentByBot",true)))
)
);
AggregationPipeline pipeline = datastore.createAggregation(A.class)
.match(datastore.createQuery(A.class).filter("sampleObjects.sentByBot", true))
.project(
projection("fieldA"),
projection("fieldB"),
filterProjection
);
Iterator<A> cursor = pipeline.aggregate(A.class, options);
while (cursor.hasNext()) {
System.out.println(morphia.toDBObject(cursor.next()));
}
}
}
@Entity(value = "example")
class A {
@Id
private ObjectId id;
private String fieldA;
private String fieldB;
@Embedded
private List<SampleObject> sampleObjects;
public A() {
}
public A(String fieldA, String fieldB) {
this.fieldA = fieldA;
this.fieldB = fieldB;
}
public void setSampleObjects(List<SampleObject> sampleObjects) {
this.sampleObjects = sampleObjects;
}
public List<SampleObject> getSampleObjects() {
return sampleObjects;
}
public ObjectId getId() {
return id;
}
public String getFieldA() {
return fieldA;
}
public void setFieldA(String fieldA) {
this.fieldA = fieldA;
}
public void setFieldB(String fieldB) {
this.fieldB = fieldB;
}
public String getFieldB() {
return fieldB;
}
}
@Embedded
class SampleObject {
private String name;
private boolean read;
private boolean sentByBot;
public SampleObject() {
}
public SampleObject(String name, boolean read, boolean sentByBot) {
this.name = name;
this.read = read;
this.sentByBot = sentByBot;
}
public String getName() {
return name;
}
public boolean isRead() {
return read;
}
public boolean isSentByBot() {
return sentByBot;
}
}
推荐阅读
- c# - 使用 OleDbConnection.Open() 时 Access-DB(.accdb) 访问崩溃应用程序
- testing - mantis中的错误1200有解决方案吗?
- javascript - After Effects:如何让一个表达在另一个已经结束后开始?
- php - 使用 implode() PHP 时数组到字符串的转换
- class - 将 Fortran 无限类可选 ARRAY 参数传递给模块中的多个子例程
- python - VAR 模型立即收敛到平均值
- python - 使用混合数据类型的特征选择
- python - 不希望 django makemigration 在数据库中创建表,因为我已经在数据库中拥有该表
- json - JSONPath 按对象中的值过滤属性
- python - 演员不会在动画中途定位