【问题标题】:Mongoid Moped query not returning the same as the MongoDB shellMongoid Moped 查询返回的结果与 MongoDB shell 不同
【发布时间】:2014-05-05 18:00:34
【问题描述】:

使用 Mongoid 3.1.5 和 MongoDB 2.4.9 创建查询我从 Mongoid/Moped 查询中得到的结果与我从等效的 MongoDB 查询中得到的结果不同。

更新添加的 Mongoid 查询 它的长查询是:

return Video.order_by(release_date: :desc, avg_rating: :desc, title: :asc)
.where( :viewable => true, :release_date.lte => start_at_date, :release_date.gte =>
start_date, :categories.in => genre_filters).any_of({:avg_rating.gt => 1},
{:avg_rating => nil}).skip(skip*POSTERS_PER_ROW).limit(limit*POSTERS_PER_ROW)
.only(:_id, :poster_large_thumb, :title, :similar_as_string, :release_date, :avg_rating)

除了genre_filters 导致只找到一个对象 afaik 之外,此查询对我抛出的所有内容都有效。

我得到以下描述 Moped 查询的控制台输出:

MOPED: 127.0.0.1:27017 QUERY        database=guide_development collection=videos 
selector={"$query"=>{"viewable"=>true, "release_date"=>{"$lte"=>2014-03-27 00:00:00 UTC,
"$gte"=>1850-01-01 00:00:00 UTC}, "categories"=>{"$in"=>["Netflix"]}, 
"$or"=>[{"avg_rating"=>{"$gt"=>1}}, {"avg_rating"=>nil}]}, "$orderby"=>
{"release_date"=>-1, "avg_rating"=>-1, "title"=>1}} 
flags=[:slave_ok] limit=60 skip=0 batch_size=nil fields={"_id"=>1,
"poster_large_thumb"=>1, "title"=>1, "similar_as_string"=>1, "release_date"=>1,
"avg_rating"=>1} (198.0939ms)

这没有返回任何结果——不是我所期望的。

一段时间后,我想出了以下 MongoDB shell 查询,它应该是等效的:

var start = new Date(2014, 3, 27);
var end - new Date(1850,1,1);

db.videos.find({
    viewable: true, release_date: {
    $lte: start, $gte: end
    }, 
    categories:{
        $in: ["Netflix"]
    }, $or: [ {avg_rating: {$gt: 1}}, {avg_rating: {$exists: false}}],
},{
    _id: 1,
    poster_large_thumb: 1,
    title: 1,
    similar_as_string: 1,
    release_date: 1,
    average_rating: 1
}).sort({release_date: -1, avg_rating: -1, title:1}).skip(0).limit(60).count()

在 MongoDB shell 中给出一个结果,这是它应该找到的一个对象。

有什么想法吗?一个对象的结果是否会导致 Mongoid 出现问题?

【问题讨论】:

  • 能否提供示例文档?

标签: ruby-on-rails mongodb mongoid mongoid3 moped


【解决方案1】:

我认为有以下区别:

avg_rating: {$exists: false}

表示返回字段不存在的结果

{"avg_rating"=>nil}

这限制了字段存在但设置为 nil 的结果。

在此处查看文档:http://docs.mongodb.org/manual/reference/operator/query/exists/

当为真时,$exists 匹配包含 字段,包括字段值为空的文档。 如果 为 false,查询只返回不包含 字段。

【讨论】:

  • 好的,轻便摩托车 {"avg_rating"=>nil} 在外壳中的等效项是什么?我只是想弄清楚为什么最初用 Ruby 编写的查询不起作用。如果我向 Netflix 添加另一个类别,例如在 Mongoid 中说“恐怖”,则会创建同一个 Moped 查询,并添加一个类别,并且所有查询都会返回一堆文档。唯一奇怪的似乎是只有一个文档有 Netflix,或者查询中只有一个类别。
【解决方案2】:

除了the difference between existence and is null,您可能还有时区问题。

Rails 和 Mongoid 将为您将时间戳转换为 UTC,您可以在 Moped 日志中看到这一点:

"release_date"=>{"$lte"=>2014-03-27 00:00:00 UTC, "$gte"=>1850-01-01 00:00:00 UTC}

Mongoid 使用 2014-03-27T00:00:00Z 和 1850-01-01T00:00:00Z 作为您的时间戳,因此您有 00:00:00 (UTC) 作为时间组件。 MongoDB 中的时间戳也将采用 UTC。

但是,当 MongoDB shell 将 2014-03-27 转换为时间戳时,它将使用当前有效的任何时区:

> new Date(2014, 3, 27)
ISODate("2014-04-27T07:00:00Z")

注意 07:00:00Z。这七个小时来自我的 PDT 时区 (GMT-0700)。因此,您应该在 MongoDB shell 中使用 ISODate 便利功能:

> ISODate('2014-03-27')
ISODate("2014-03-27T00:00:00Z")
> ISODate('1850-01-01')
ISODate("1850-01-01T00:00:00Z")

以确保您获得正确的时区。

另外,由于您只查看计数,您可以在 MongoDB shell 中省略 find 的第二个参数以简化操作。或者使用{ _id: true } 并删除count() 以减少混乱。

修复tirdadc 和我指出的问题,看看你在这两种情况下是否得到相同的结果。如果你不这样做,那么开始逐个构建两个查询,直到它们产生不同的结果,你就会知道问题出在哪里。不要忘记从一开始就包含排序选项,并比较返回的文档 ID 而不仅仅是计数。

【讨论】:

  • 整个场景都在我的开发机器上运行,所以我相信时区不是问题。优化查询值得赞赏,但不是问题。我可能没有最佳查询,但为什么我从一台机器上得到结果,而在同一台机器上使用相同的数据库却一无所获。
  • 不信,求证。 new Date(2014, 3, 27) 在 MongoDB shell 中说什么?切换到ISODate 有什么改变吗?
  • 我有其他 order_by 查询以不使用发布日期的方式排序,它们给出相同的结果,没有返回数据。我刚从发布日期排序开始,所以现在必须坚持下去。例如,有一个不指定日期范围的按标题排序查询,当类别 = ["Netflix"] 时返回 0,当类别 = ["Horror", "Netflix"] 时返回一堆。由于单个 Netflix 电影是一部恐怖电影,因此它会在任何指定 categories = ["Horror", "Netflix"] 的查询中返回
  • 我尝试了一堆batchSize值,注意轻便摩托车说batchSize = nil。但没有一个对结果有任何影响。 shell 查询始终有效,Mongoid 永远无效。
  • 您确定 Mongoid 和 MongoDB shell 正在与同一个数据库通信吗?
猜你喜欢
  • 2016-11-18
  • 1970-01-01
  • 2012-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多