首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Mongoid查找不包含任何属性的对象

使用Mongoid查找不包含任何属性的对象
EN

Stack Overflow用户
提问于 2014-04-10 00:05:50
回答 1查看 195关注 0票数 0

使用Mongoid,如何查询不包含特定属性的对象?

具体来说,我正在寻找所有的课程对象,其中Course.prerequisite_courses不包括Student.courses_taken以外的任何课程。

例如:

代码语言:javascript
复制
Class Student
  include Mongoid::Document

  field :courses_taken,    type: Array # an array of course IDs
end

Class Course
  include Mongoid::Document

  field :prerequisites,    type: Array # an array of course IDs
end

student_1.courses_taken = [a, b]

course_1.prerequisites = [a]

course_2.prerequisites = [a, b]

course_3.prerequisites = [a, c]

这样student_1就可以被course_1和course_2录取,而不是course_3

这两个物体是不相关的

请注意,在本例中,可能有数百个course.prerequisites和student.courses_taken,我打算让这只是我的查询中的几个链式方法之一。

是否有一种优雅(或至少相对便宜)的方法来处理蒙古查询?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-04-10 02:28:02

我确实有一个普遍的偏好,因为是在一个较低的水平上工作,并允许您充分利用MongoDB查询运算符的全部功能集。对某些人来说,这可能不是很“粗俗”的,但也有一些好处。特别是当解决方案涉及到.aggregate()的使用时

因此,为了找到与学生所修课程的先决条件相匹配的课程,您可以建立这样的声明:

代码语言:javascript
复制
Course.collection.aggregate([
    // Filters the documents, not an exact match but a start
    { "$match" => { 
        "prerequisites" => { "$in" => [ "a", "b" ] },
    }},

    // Unwind the array
    { "$unwind" => "$prerequisites" },

    // Tag only the matching entries
    { "$project" => {
        "prerequisites" => 1,
        "matching" => { "$or" => [
            { "$eq" => [ "$prerequisites", "a" ] },
            { "$eq" => [ "$prerequisites", "b" ] },
        ]}
    }},

    // Group back to the course _id
    { "$group" => {
        "_id" => "$_id",
        "prerequisites" => { "$push" => "$prerequisites" },
        "matching" => { "$min" => "$matching" }
    }},

    // Match only the true values (all prerequisites met )
    { "$match" => { "matching" => true } },

    // Project only the wanted fields
    { "$project" => { "prerequisites" => 1 } }
])

因此,"courses_taken“的每个元素都被添加到$in运算符中,因此只有包含某些内容的课程才能在初始阶段匹配。但这当然不能完全过滤学生必须满足所有必修课的条件,这里的重点是将文档数量减少到可能匹配的文档数量。

在打开数组后,可以比较每个值。这就是$project通过从数组元素构建语句来测试是否找到该值所做的事情。因此,在这个$or条件下,任何不匹配的东西都会返回false作为这个值。

在后期的$group阶段,当文档被放回原来的形式时,“匹配”测试的$min值将存储在文档中。这意味着如果先决条件数组的任何元素被视为false匹配,那么整个文档的值将被视为false

下一个$match用于筛选出任何课程,这些课程包含的课程先决条件与用于输入的学生所选课程不匹配。因此,现在只剩下可以参加的课程了,最后的$project只是删除了“匹配”字段(省略了),所以文档现在是原始的了。

如果您实际上拥有MongoDB版本2.6 (编写时刚刚发布)或更高版本,那么有新的聚合操作符可以使语句更加简单:

代码语言:javascript
复制
Course.collection.aggregate([
    { "$match" => { 
        "prerequisites" => { "$in" => [ "a", "b" ] }
    }},
    { "$project" => {
        "prerequisites" => 1,
        "diff" => { "$size" => {"$setDifference" => [ 
            "$prerequisites", 
            [ "a", "b" ] 
        ]}}
    }},
    { "$match" => { "diff" => 0  } },
    { "$project" => { "prerequisites" => 1 } }
])

因此,这就利用了$setDifference的新运算符,它可以直接比较数组以查找不在集合中的元素,以及使用$size返回测试数组的长度。因为任何包含未在为学生所选课程数组中的prerequsite元素的课程将返回这些元素作为*$setDifference的结果,所以除0之外的任何结果都可以被排除在整个结果之外。

除了简单得多和具有一些速度优势之外,您还可以将课程数组从学生直接传递到管道查询的构建中,从而避免了生成中的复杂性,并且不必在第一个示例中使用的构造“相等”测试语句时乱搞。

但是这给了您相当强大的方法来完成这种匹配,而不需要在代码中循环结果。它还指出,聚合框架的使用不仅用于分组结果,而且是一个非常强大的查询工具。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22976221

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档