Java Morphia:在嵌入对象列表中搜索空值
我有一个嵌入式实体列表:Java Morphia:在嵌入对象列表中搜索空值,java,mongodb,morphia,Java,Mongodb,Morphia,我有一个嵌入式实体列表: @Embedded private List<EmbeddedEntity> embedded = new ArrayList<EmbeddedEntity>(); 如果列表为空,或者只有一个条目,其中foo有一个值,而bar还不存在,则此选项可以正常工作。但是,只要任何bar属性有一个值,查询就会返回错误的结果。因此,我正在寻找一个查询,它遍历所有嵌入的实体,并在任何缺少的条上激发。可能吗 示例数据: // the query does no
@Embedded
private List<EmbeddedEntity> embedded = new ArrayList<EmbeddedEntity>();
如果列表为空,或者只有一个条目,其中foo有一个值,而bar还不存在,则此选项可以正常工作。但是,只要任何bar属性有一个值,查询就会返回错误的结果。因此,我正在寻找一个查询,它遍历所有嵌入的实体,并在任何缺少的条上激发。可能吗
示例数据:
// the query does not pick up the entity as it doesn't have a foo -
// that's what I want
{ uuid: "...", [ { embedded: } ] }
// the query picks up the entity as there is a foo but no bar -
// that's what I want
{ uuid: "...", [ { embedded: { foo: date } } ] }
// the query does not pick up the entity - that's not what I want
// as one foo has a value and its bar doesn't
{ uuid: "...", [ { embedded: { foo: date, bar: date } },
{ embedded: { foo: date } }
] }
PS:我用.fieldembedded.bar.hasThisOneFull得到了相同的结果
PPS:手动迭代列表元素实际上不是一个选项,因为我想使用查询进行更新操作
PPS:我认为这是Morphia中的一个bug-请参阅下面我的答案以了解解决方法我找到了一个解决方法。虽然我似乎无法查询null,但我可以查询特定的值 在我的例子中,bar字段是一个日期。因此,我可以用private Date bar=new Date0初始化实体-在我的例子中,这显然是一个无效的日期,从未使用过。因此,查询如下所示:
Query<Entity> query = mongoDataStore
.find(Entity.class)
.field("uuid").equal(uuid)
.field("embedded.foo").exists()
.field("embedded.bar").hasThisOne(new Date(0));
我找到了一个解决办法。虽然我似乎无法查询null,但我可以查询特定的值 在我的例子中,bar字段是一个日期。因此,我可以用private Date bar=new Date0初始化实体-在我的例子中,这显然是一个无效的日期,从未使用过。因此,查询如下所示:
Query<Entity> query = mongoDataStore
.find(Entity.class)
.field("uuid").equal(uuid)
.field("embedded.foo").exists()
.field("embedded.bar").hasThisOne(new Date(0));
我认为您的模式在概念上有问题。请记住,您总是查询顶级文档。查询不起作用的原因是,您要求它返回顶级文档,其中至少一个元素具有foo,而至少一个元素没有bar值。请注意,这两个条件不必应用于同一数组元素 您可以使用$elemMatch在MongoDB中执行您想要的操作: 查找{embedded:{$elemMatch:{foo:{$exists:true},bar:{$exists:false}}},如下所示:
> db.test.save({embedded:[]})
> db.test.save({embedded:[{foo:1}]})
> db.test.save({embedded:[{bar:1}]})
> db.test.save({embedded:[{foo:1, bar:1}]})
> db.test.find({embedded:{$elemMatch:{foo:{$exists:true}, bar:{$exists:false}}}})
{ "_id" : ObjectId("4f60c4d56fa40267a11d2f2c"), "embedded" : [ { "foo" : 1 } ] }
如果null是bar的有效值,您只需将其更改为:
> db.test.save({embedded:[{foo:1, bar:null}]})
> db.test.find({embedded:{$elemMatch:{foo:{$exists:true}, $or:[{bar:{$exists:false}}, {bar:null}]}}})
{ "_id" : ObjectId("4f60c4d56fa40267a11d2f2c"), "embedded" : [ { "foo" : 1 } ] }
{ "_id" : ObjectId("4f60c52a6fa40267a11d2f30"), "embedded" : [ { "foo" : 1, "bar" : null } ] }
现在,在Morphia中,$elemMatch由FieldEnd方法hasThisElement包装。我不太熟悉我编写的Morphia并使用我自己的映射器,但这应该将带有上述子句的DBObject作为它的值,这应该导致您需要执行的操作
但同样,这将返回顶级文档,这些文档的嵌入数组中包含符合这些条件的元素。如果只想返回匹配的元素,则可能必须在顶级集合中转换嵌入的结构。如果更新仅涉及通过$positional运算符修改匹配元素,则已足够:
db.test.update(
{embedded:{$elemMatch:{foo:{$exists:true}, $or:[{bar:{$exists:false}}, {bar:null}]}}},
{$set:{'embedded.$.bar':"yay!"}}
)
我认为您的模式在概念上有问题。请记住,您总是查询顶级文档。查询不起作用的原因是,您要求它返回顶级文档,其中至少一个元素具有foo,而至少一个元素没有bar值。请注意,这两个条件不必应用于同一数组元素 您可以使用$elemMatch在MongoDB中执行您想要的操作: 查找{embedded:{$elemMatch:{foo:{$exists:true},bar:{$exists:false}}},如下所示:
> db.test.save({embedded:[]})
> db.test.save({embedded:[{foo:1}]})
> db.test.save({embedded:[{bar:1}]})
> db.test.save({embedded:[{foo:1, bar:1}]})
> db.test.find({embedded:{$elemMatch:{foo:{$exists:true}, bar:{$exists:false}}}})
{ "_id" : ObjectId("4f60c4d56fa40267a11d2f2c"), "embedded" : [ { "foo" : 1 } ] }
如果null是bar的有效值,您只需将其更改为:
> db.test.save({embedded:[{foo:1, bar:null}]})
> db.test.find({embedded:{$elemMatch:{foo:{$exists:true}, $or:[{bar:{$exists:false}}, {bar:null}]}}})
{ "_id" : ObjectId("4f60c4d56fa40267a11d2f2c"), "embedded" : [ { "foo" : 1 } ] }
{ "_id" : ObjectId("4f60c52a6fa40267a11d2f30"), "embedded" : [ { "foo" : 1, "bar" : null } ] }
现在,在Morphia中,$elemMatch由FieldEnd方法hasThisElement包装。我不太熟悉我编写的Morphia并使用我自己的映射器,但这应该将带有上述子句的DBObject作为它的值,这应该导致您需要执行的操作
但同样,这将返回顶级文档,这些文档的嵌入数组中包含符合这些条件的元素。如果只想返回匹配的元素,则可能必须在顶级集合中转换嵌入的结构。如果更新仅涉及通过$positional运算符修改匹配元素,则已足够:
db.test.update(
{embedded:{$elemMatch:{foo:{$exists:true}, $or:[{bar:{$exists:false}}, {bar:null}]}}},
{$set:{'embedded.$.bar':"yay!"}}
)
您要求它返回顶级文档,其中至少一个元素具有foo,并且至少一个元素没有bar值。请注意,这两个条件不必应用于同一数组元素。这正是我想要的——它们不需要在同一个元素上。如果任何条形字段具有值,则上述查询将失败。我想要顶级的收藏,这就足够了。嗯,那样的话,我对你的要求有点不清楚。你能用样本数据和你的查询结果扩展你的原始帖子吗?就像我在回答中所做的那样。它使阅读更容易。你说失败是什么意思?在应该返回结果时不返回结果?投掷错误?在不应该返回结果的时候返回结果?我试图澄清并添加了一个示例。我下面的答案产生了期望的结果……在这种情况下,我的解决方案仍然有效。您必须使用$elemMatch或与之相当的Morphia。这将扫描每个元素,并允许您查询至少一个包含foo但不包含bar但可以包含其他元素的元素
对于$elemMatch,具有两种形式等价物的ts为.hasThisElementvalue。但是,.fieldembedded.bar.hasThisElementnull;阻塞错误,因为该值为空。这可能是一个Morphia问题,而不是与MongoDB相关,但感谢您在数据库级别澄清这一点!您要求它返回顶级文档,其中至少一个元素具有foo,并且至少一个元素没有bar值。请注意,这两个条件不必应用于同一数组元素。这正是我想要的——它们不需要在同一个元素上。如果任何条形字段具有值,则上述查询将失败。我想要顶级的收藏,这就足够了。嗯,那样的话,我对你的要求有点不清楚。你能用样本数据和你的查询结果扩展你的原始帖子吗?就像我在回答中所做的那样。它使阅读更容易。你说失败是什么意思?在应该返回结果时不返回结果?投掷错误?在不应该返回结果的时候返回结果?我试图澄清并添加了一个示例。我下面的答案产生了期望的结果……在这种情况下,我的解决方案仍然有效。您必须使用$elemMatch或与之相当的Morphia。这将扫描每个元素,并允许您查询至少一个包含foo但不包含bar的元素,但可以包含其他元素,这些元素在$elemMatch is.hasThisElementvalue中具有相同的外观。但是,.fieldembedded.bar.hasThisElementnull;阻塞错误,因为该值为空。这可能是一个Morphia问题,而不是与MongoDB相关,但感谢您在数据库级别澄清这一点!