MongoDB Array Query
本文关键字:Query Array MongoDB | 更新日期: 2023-09-27 18:04:36
我是新的mongodb,我想弄清楚如何做一些更复杂的查询。我有一个文档,它有一个嵌套的DateTime
数组。
这是我的数据:
{ "_id" : ObjectId("537d0b8c2c6b912520798b76"), "FirstName" : "Mary", "LastName" : "Johnson", "Age" : 27, "Phone" : "555 555-1212", "Dates" : [ISODate("2014-05-21T21:34:16.378Z"), ISODate("1987-01-05T08:00:00Z")] }
{ "_id" : ObjectId("537e4a7e2c6b91371c684a34"), "FirstName" : "Walter", "LastName" : "White", "Age" : 52, "Phone" : "800 123-4567", "Dates" : [ISODate("1967-12-25T08:00:00Z"), ISODate("2014-12-25T08:00:00Z")] }
我想做的是返回文档,其中日期数组包含一个范围之间的值。在我的测试用例中,范围是1/1/1987和1/10/1987,所以我希望得到上面列出的第一个文档(Mary Johnson),因为1/5/1987在日期数组中,并且位于1/1/1987和1/10/1987之间。
我想能够做到这一点与MongoDB命令行实用程序和c#驱动程序。
使用c#驱动程序,我尝试了以下LINQ查询(基于MongoDB文档中的示例):
DateTime beginRange = new DateTime(1987, 1, 1);
DateTime endRange = new DateTime(1987, 1, 10);
var result = from p in people.AsQueryable<Person>()
where p.Dates.Any(date => date > beginRange && date < endRange)
select p;
上面的代码从c#驱动程序代码中抛出一个异常:
Any
仅支持序列化为文档的项。当前的序列化器是DateTimeSerializer
,必须实现IBsonDocumentSerializer
才能参与Any
查询。
当我尝试直接查询MongoDB数据库时,我尝试了以下操作:
db.People.find( {Dates: { $gt: ISODate("1987-01-01"), $lt: ISODate("1987-01-10") } } )
这个查询的结果是两个文档都返回,而不是只有一个在Dates
数组中有1/5/1987
的文档返回。
我从c#驱动程序中找到了一种方法。它不像我想的那么干净,但它是可行的。
我想,既然有一种方法可以直接从命令实用程序中获得我想要的东西,那么必须有一种方法可以通过从c#驱动程序中执行相同的查询来从c#驱动程序中执行。
string command = "{Dates : { $elemMatch : { $gt: ISODate('"" + beginRange.ToString("yyyy-MM-dd") + "'"), $lt: ISODate('"" + endRange.ToString("yyyy-MM-dd") + "'") } } } ";
var bsonDoc = BsonSerializer.Deserialize<BsonDocument>(command);
var queryDoc = new QueryDocument(bsonDoc);
MongoCursor<Person> p = people.Find(queryDoc);
c# Driver
正如异常所暗示的那样,只要数组是原始类型(DateTime
)而不是真正的文档,就不能使用c#驱动程序做你想做的事情。
来自MongoDB Linq Any
的描述:
只有当枚举对象的元素被序列化为文档时才会起作用。有一个服务器错误阻止此操作针对原语。
我猜你可以在DateTime
值周围创建一个文档包装器所以你仍然可以这样做:
var result = people.AsQueryable<Person>().Where(
person => person.Dates.Any(date =>
date.Value > beginRange && date.Value < endRange));
.
public class DocumentWrapper<T>
{
public ObjectId Id { get; private set; }
public T Value { get; private set; }
public DocumentWrapper(T value)
{
Id = ObjectId.GenerateNewId();
Value = value;
}
}
原生查询
对于您的查询,它实际上并不等同于Linq查询。那就是:
{
Dates :
{
$elemMatch :
{
$gt: ISODate("1987-01-01"),
$lt: ISODate("1987-01-10")
}
}
}
关于$elemMatch的更多信息