Mongodb查询与相同文档中的字段

时间:2011-12-08 15:05:32

标签: mongodb

我有下一个json。

{
  "a1": {"a": "b"},
  "a2": {"a": "c"}
}

我想要请求所有文件,其中a1不等于同一文件中的a2。

我怎么做?

6 个答案:

答案 0 :(得分:73)

您可以使用$where

db.myCollection.find( { $where: "this.a1.a != this.a2.a" } )

但是,要注意这不会很快,因为它必须启动java脚本引擎并迭代每个文档并检查每个文档的条件。

如果您需要对大型集合执行此查询,或者经常,最好引入非正规化标记,如areEqual。尽管如此,这种低选择性字段并不能产生良好的索引性能,因为候选集仍然很大。

答案 1 :(得分:21)

为避免JavaScript使用聚合框架:

def enqueue(elems : A*) 

在我们的开发服务器上,等效的JavaScript查询需要7倍的时间才能完成。

更新(2017年5月10日)

我刚刚意识到我的回答并没有回答这个问题,这个问题想要的价值不相等(有时我真的很慢)。这将适用于此:

db.myCollection.aggregate([
  {"$match":{"a1":{"$exists":true},"a2":{"$exists":true}}},
  {"$project": {
      "a1":1,
      "a2":1,
      "aCmp": {"$cmp":["$a1.a","$a2.a"]}
    }
  },
  {"$match":{"aCmp":0}}
])
如果匹配条件更改为db.myCollection.aggregate([ {"$match":{"a1":{"$exists":true},"a2":{"$exists":true}}}, {"$project": { "a1":1, "a2":1, "aEq": {"$eq":["$a1.a","$a2.a"]} } }, {"$match":{"aEq": false}} ]) ,则可以使用

$ne代替$eq,但我发现使用true $eq更直观

答案 2 :(得分:6)

更新

使用从mongo 3.6开始提供的新$expr运算符,您可以在查询查询中使用聚合表达式,如下所示:

  db.myCollection.find({$expr: {$ne: ["$a1.a", "$a2.a"] } });

虽然this comment解决了这个问题,但我认为这个用例的更好匹配是使用版本3.4而不是$ project的$addFields运算符。

db.myCollection.aggregate([
     {"$match":{"a1":{"$exists":true},"a2":{"$exists":true}}},
     {"$addFields": {
           "aEq": {"$eq":["$a1.a","$a2.a"]}
         }
     },
     {"$match":{"aEq": false}} 
  ]);

答案 3 :(得分:4)

MongoDB在后台使用Javascript,所以

{"a": "b"} == {"a": "b"}

将是false

所以要比较每个你需要a1.a == a2.a

要在MongoDB中执行此操作,您将使用$ where运算符

db.myCollection.find({$where: "this.a1.a != this.a2.a"});

这假设每个嵌入式文档都有一个属性" a"。如果不是这样的话,情况会变得更复杂。

答案 4 :(得分:2)

Mongo 4.4开始,对于那些想要比较子文档的人,不仅要原始值(因为{"a": "b"} == {"a": "b"}false),我们可以使用新的$function聚合运算符,允许应用自定义javascript函数:

// { "a1" : { "x" : 1, "y" : 2 }, "a2" : { "x" : 1, "y" : 2 } }
// { "a1" : { "x" : 1, "y" : 2 }, "a2" : { "x" : 3, "y" : 2 } }
db.collection.aggregate(
  { $match:
    { $expr:
      { $function: {
          body: function(a1, a2) { return JSON.stringify(a1) != JSON.stringify(a2); },
          args: ["$a1", "$a2"],
          lang: "js"
      }}
    }
  }
)
// { "a1" : { "x" : 1, "y" : 2 }, "a2" : { "x" : 3, "y" : 2 } }

$function具有3个参数:

  • body,这是要应用的函数,其参数是要比较的两个字段。
  • args,其中包含body函数作为参数的记录中的字段。在我们的情况下,"$a1""$a2"都是如此。
  • lang,这是编写body函数的语言。当前仅js可用。

答案 5 :(得分:0)

感谢所有人解决我的问题-关于使用aggregate()的答案,首先让我感到困惑的一件事是,$ eq(或$ in,或许多其他运算符)根据其位置而具有不同的含义。用过的。在find()或聚合的$ match阶段,$ eq取一个值,然后选择匹配的文档:

db.items.aggregate([{$match: {_id: {$eq: ObjectId("5be5feb45da16064c88e23d4")}}}])

但是,在聚合的$ project阶段,$ eq接受2个表达式组成的数组,并创建一个值为true或false的新字段:

db.items.aggregate([{$project: {new_field: {$eq: ["$_id", "$foreignID"]}}}])

顺便说一句,这是我在项目中使用的查询,用于查找所有链接到其自身的链接项列表(由于错误)的项:

db.items.aggregate([{$project: {idIn: {$in: ["$_id","$header.links"]}, "header.links": 1}}, {$match: {idIn: true}}])