web-dev-qa-db-ja.com

フィールドごとのMongoDB集約が存在する

私は、この質問がどこかで既に尋ねられて、答えられていないと信じるのに苦労します、しかし、私はそれの少しの痕跡も見つけることができません。

ブール値でグループ化する必要があるMongoDB集計クエリがあります:別のフィールドの存在。

たとえば、このコレクションから始めましょう。

> db.test.find()
{ "_id" : ObjectId("53fbede62827b89e4f86c12e"),
  "field" : ObjectId("53fbede62827b89e4f86c12d"), "name" : "Erik" }
{ "_id" : ObjectId("53fbee002827b89e4f86c12f"), "name" : "Erik" }
{ "_id" : ObjectId("53fbee092827b89e4f86c131"),
  "field" : ObjectId("53fbee092827b89e4f86c130"), "name" : "John" }
{ "_id" : ObjectId("53fbee122827b89e4f86c132"), "name" : "Ben" }

2つのドキュメントには「フィールド」があり、2つにはありません。 「フィールド」の各値は異なる場合があることに注意してください。その存在に基づいてグループ化したいだけです(または、null以外の場合も機能します。null値は保存されていません)。

$ projectを使用してみましたが、$ existsは存在せず、$ condと$ ifNullは役に立ちませんでした。フィールドは、存在しない場合でも常に存在するように見えます。

> db.test.aggregate(
  {$project:{fieldExists:{$cond:[{$eq:["$field", null]}, false, true]}}},
  {$group:{_id:"$fieldExists", count:{$sum:1}}}
)
{ "_id" : true, "count" : 4 }

次のはるかに単純な集計が機能することを期待しますが、何らかの理由でこの方法では$ existsはサポートされていません。

> db.test.aggregate({$group:{_id:{$exists:"$field"}, count:{$sum:1}}})
assert: command failed: {
  "errmsg" : "exception: invalid operator '$exists'",
  "code" : 15999,
  "ok" : 0
} : aggregate failed
Error: command failed: {
  "errmsg" : "exception: invalid operator '$exists'",
  "code" : 15999,
  "ok" : 0
} : aggregate failed
    at Error (<anonymous>)
    at doassert (src/mongo/Shell/assert.js:11:14)
    at Function.assert.commandWorked (src/mongo/Shell/assert.js:244:5)
    at DBCollection.aggregate (src/mongo/Shell/collection.js:1149:12)
    at (Shell):1:9
2014-08-25T19:19:42.344-0700 Error: command failed: {
  "errmsg" : "exception: invalid operator '$exists'",
  "code" : 15999,
  "ok" : 0
} : aggregate failed at src/mongo/Shell/assert.js:13

このようなコレクションから望ましい結果を得る方法を知っている人はいますか?

期待される結果:

{ "_id" : true, "count" : 2 }
{ "_id" : false, "count" : 2 }
38
Erik

私は昨夜、同じ方法でこの問題を解決しました:

> db.test.aggregate({$group:{_id:{$gt:["$field", null]}, count:{$sum:1}}})
{ "_id" : true, "count" : 2 }
{ "_id" : false, "count" : 2 }

http://docs.mongodb.org/manual/reference/bson-types/#bson-types-comparison-order をご覧ください。

64
kdkeck

未定義をチェックして解決しました

$ne : [$var_to_check, undefined]

または

$ne:  [ { $type : "$var_to_check"}, 'missing'] }

Varが定義されている場合、これはtrueを返します

11
Delcon

$exists 演算子は「クエリ」演算子であるため、基本的に結果を「フィルタリング」するために使用されます論理条件を識別するよりも。

「論理」演算子として、集計フレームワークは $ifNull 演算子をサポートします。これは、存在するフィールド値、または存在しないか、nullと評価される代替提供値を返します。

db.test.aggregate([
    { "$group": {
        "_id": { "$ifNull": [ "$field", false ] },
        "count": { "$sum": 1 }
    }}
])

しかし、もちろん、それは「true/false」比較ではないので、実際にフィールドが存在するフィールドの実際の値を返さない限り、おそらく $cond あなたのような文:

db.test.aggregate([
    { "$group": {
        "_id": { "$cond": [{ "$eq": [ "$field", null ] }, true, false ] },
        "count": { "$sum": 1 }
    }}
])

$ifNull が非常に役立つのは、$unwind。その後、単一要素または空の配列を返すなどの操作を行うことができるため、残りのパイプライン処理で問題が発生することはありません。

9
Neil Lunn

ダンノはどうだったが、今では2019年にクリーンなソリューションがあります。集約パイプラインでこれを行います

$match: {"my_field": {$ne: null}}

素敵なことは私の言語にあります 'ne'はないことを意味します:)

3
djuleAyo

私の答えは:

{'$project': {
    'field_exists': {'$or': [
        {'$eq': ['$field', null]}, 
        {'$gt': ['$field', null]},
    ]},
}}

詳細は次のとおりです。 $ existsは、nullまたはその他の空の値であっても、フィールドが存在することを意味します。このため、このページのすべての回答が間違っています。

少しテストしてみましょう。これをチェックして:

// Let's take any collection that have docs
db.getCollection('collection').aggregate([
  // Get arbitrary doc, no matter which, we won't use it
  {"$limit": 1},
  // Project our own fields (just create them with $literal)
  {'$project': {
    '_id': 0,
    'null_field': {'$literal': null},
    'not_null_field': {'$literal': {}},
  }},
])

これを取得します。

{
    "null_field" : null,
    "not_null_field" : {}
}

次に、このドキュメントに存在するフィールドを明確にしましょう。

  1. null_field-存在
  2. not_null_field-存在します
  3. non_existent_field-しません。

さて、上で述べたプロジェクト段階をテストする時が来ました。興味のあるすべてのフィールドに追加しましょう:

{'$project': {
    'null_field_exists': {'$or': [
        {'$eq': ['$null_field', null]}, 
        {'$gt': ['$null_field', null]},
    ]},
    'not_null_field_exists': {'$or': [
        {'$eq': ['$not_null_field', null]}, 
        {'$gt': ['$not_null_field', null]},
    ]},
    'non_existent_field_exists': {'$or': [
        {'$eq': ['$non_existent_field', null]}, 
        {'$gt': ['$non_existent_field', null]},
    ]},
}},

私たちが得るものは:

{
    "null_field_exists" : true,
    "not_null_field_exists" : true,
    "non_existent_field_exists" : false
}

正しい!

ちょっとした注意:nullを比較に使用します。これは、少なくとも価値があるため、最も小さい値です(小さいほど、存在しないだけです)。

1
egvo