使用Morphia返回匹配的数组元素 [英] Return matching Array Elements with Morphia

查看:400
本文介绍了使用Morphia返回匹配的数组元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一种方法,在提供一些条件后,从给定的对象列表中过滤掉所有对象

I am looking for a way to filter out all objects from a given List of Object after providing some conditions.

例如

@Entity(value = "tbl_A")
public class A {

private String notes;
@Embedded
private List<SampleObject> sampleObject;

....getter and setter ...
}



< h1> B类

Class B

@Embedded
public class SampleObject {
    private boolean read;
    private boolean sentByBot;

   ... getter and setter ...
   }

现在,我只想收集 SampleObject ,其中 sentByBot 参数设置为 true 。我使用以下方法:

Now, I only want to collect the SampleObject which does have sentByBot parameter set to true. I am using following approach:

Query<A> queryForA = datastore.find(A.class);
queryForA.field("sampleObject.sentByBot").equal(false).retrievedFields(true, "sampleObject.sentByBot");

上面的代码给出了对象的完整列表其中 sampleObject.sentByBot true和false两者。

Above code is giving me the whole list of objects which have sampleObject.sentByBot true and false both.

我也试过过滤器方法即

 queryForA.filter("sampleObject.sentByBot", false).retrievedFields(true, "sampleObject.sentByBot");

但没有运气。有没有办法让这些字段只有 sampleObject.sentByBot 设置为真?

But no luck. Is there any way to get those fields only which have sampleObject.sentByBot set true?

实现以下代码后我得到了这个:

After implementing following code I got this:

  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);



输出



Output

"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发布这样的聚合语句,你需要这样的东西:

As stated earlier, what you want in order to only return "multiple" array elements which match a given condition is the $filter aggregation pipeline operator in projection. In order to issue such an aggregation statement with Morphia you want something like this:

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 ] }
      }
    }
  }}
]

并且只返回符合条件的匹配文档中的数组元素:

And returns only array elements from the matching documents that also match the condition:

{ 
  "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}
  ]
}

请注意,您需要构建 e xpression()在参数中手动从 DBObject(),因为Morphia中没有支持此类操作的当前构建器。预计将来的版本将更改为 Document 接口,该接口已经在基础Java驱动程序中标准化了一段时间。

Note that you need to build the expression() in argument manually from DBObject() as there are no current "builders" supported in Morphia for this type of operation. It would be expected that future releases would change to the Document interface which has been standard in the underlying Java driver for some time now.

作为完整示例列表:

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;
    }
}

这篇关于使用Morphia返回匹配的数组元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆