Java 返回与Morphia匹配的数组元素

Java 返回与Morphia匹配的数组元素,java,mongodb,mongodb-query,aggregation-framework,morphia,Java,Mongodb,Mongodb Query,Aggregation Framework,Morphia,我正在寻找一种方法,在提供一些条件之后,从给定的对象列表中筛选出所有对象 比如说 甲级 现在,我只想收集SampleObject,它的sentbybbot参数设置为true。我采用以下方法: Query<A> queryForA = datastore.find(A.class); queryForA.field("sampleObject.sentByBot").equal(false).retrievedFields(true, "sampleObject.sentByBot")

我正在寻找一种方法,在提供一些
条件之后,从给定的
对象列表中筛选出所有对象

比如说

甲级 现在,我只想收集
SampleObject
,它的
sentbybbot
参数设置为
true
。我采用以下方法:

Query<A> queryForA = datastore.find(A.class);
queryForA.field("sampleObject.sentByBot").equal(false).retrievedFields(true, "sampleObject.sentByBot");
但是没有运气。有没有办法只获取那些将sampleObject.Sentbybbot设置为true的字段

编辑 在实现以下代码后,我得到了以下结果:

数据库映像

代码
如前所述,为了只返回与给定条件匹配的“多个”数组元素,您需要的是投影中的聚合管道操作符。为了向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}
  ]
}
请注意,您需要从
DBObject()
手动生成
expression()
in参数,因为Morphia中不支持这种类型的操作。预计未来的版本将更改为
文档
接口,该接口在底层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;
    }
}
package com.snakier.example;
导入com.mongodb.AggregationOptions;
导入com.mongodb.BasicDBObject;
导入com.mongodb.MongoClient;
导入org.bson.types.ObjectId;
导入org.mongodb.morphia.Datastore;
导入org.mongodb.morphia.morphia;
导入org.mongodb.morphia.aggregation.AggregationPipeline;
导入org.mongodb.morphia.aggregation.Projection;
导入org.mongodb.morphia.annotations.Embedded;
导入org.mongodb.morphia.annotations.Entity;
导入org.mongodb.morphia.annotations.Id;
导入java.util.array;
导入java.util.Iterator;
导入java.util.List;
导入静态org.mongodb.morphia.aggregation.Projection.*;
公共类应用程序{
公共静态void main(字符串[]args){
最终Morphia Morphia=新Morphia();
mapPackage(“com.snakier.example”);
final Datastore Datastore=morphia.createDatastore(新的MongoClient(),“示例”);
//干净示例数据库
datastore.getDB().getCollection(“示例”).drop();
//创建一些数据
最终A第一=新A(“某物”、“其他”);
最后一秒=新的A(“另一个”,“事物”);
最终SampleObject firstSample=新的SampleObject(“一”,假,真);
最终SampleObject secondSample=新的SampleObject(“两个”,假,假);
最终SampleObject thirdSample=新的SampleObject(“三”,真,真);
最终SampleObject fourthSample=新的SampleObject(“四”,真,假);
first.setSampleObjects(Arrays.asList(firstSample、secondSample、thirdSample));
datastore.save(第一);
其次,设置采样对象(Arrays.asList(fourthSample));
数据存储。保存(秒);
AggregationOptions=AggregationOptions.builder()
.outputMode(聚合选项.outputMode.CURSOR)
.build();
//System.out.println(options.toString());
投影过滤器投影=投影(
“采样对象”,
表情(
“$filter”,
新的BasicDBObject(“输入”,“$sampleObjects”)
.append(“cond”,新的BasicDBObject($eq),Arrays.asList($this.sentbybbot),true)))
)
);
AggregationPipeline=datastore.createAggregation(A.class)
.match(datastore.createQuery(A.class).filter(“sampleObjects.sentbybbot”,true))
.项目(
投影(“fieldA”),
投影(“字段B”),
过滤喷射
);
迭代器游标=pipeline.aggregate(A.class,options);
while(cursor.hasNext()){
System.out.println(morphia.toDBObject(cursor.next());
}
}
}
@实体(value=“示例”)
甲级{
@身份证
私有ObjectId;
私有字符串字段a;
私有字符串字段b;
@嵌入
私有列表样本对象;
公共A(){
}
公共A(字符串字段A、字符串字段B){
this.fieldA=fieldA;
this.fieldB=fieldB;
}
public void设置采样对象(列出采样对象){
this.sampleObjects=sampleObjects;
}
公共列表getSampleObjects(){
返回样本对象;
}
公共ObjectId getId(){
返回id;
}
公共字符串getFieldA(){
返回场A;
}
公共无效集合字段A(字符串字段A){
this.fieldA=fieldA;
}
公共无效集合字段B(字符串字段B){
this.fieldB=fieldB;
}
公共字符串getFieldB(){
返回字段B;
}
}
@嵌入
类采样对象{
私有字符串名称;
私有布尔读取;
私有布尔Sentbot;
公共样本对象(){
}
公共SampleObject(字符串名称、布尔读取、布尔Sentbybbot){
this.name=名称;
this.read=read;
this.sentByBot=sentByBot;
}
公共字符串getName(){
返回名称;
}
公共布尔值isRead(){
返回读取;
}
公共布尔值isSentByBot(){
返回sentByBot;
}
}

如上所示,您想要的实际上是由聚合运算符实现的。以这种方式“修改文档”不是常规查询表达式的工作,您最多只能使用常规查询返回。您需要为此构造聚合语句。@NeilLunn我如何在
morphia
中实现
$filter
?感谢您的解释和示例,但我得到了这个错误
$filter仅支持对象作为其参数“
迭代器游标=pipeline.aggregate(A.clas
"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 }"
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}
  ]
}
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;
    }
}