特定の値を含む配列を持つドキュメントを検索します


499

このスキーマがある場合...

person = {
    name : String,
    favoriteFoods : Array
}

... favoriteFoods配列には文字列が入力されます。マングースを使って、好きな食べ物として「寿司」を持っている人をすべて見つけるにはどうすればよいですか。

私は次の線に沿って何かを望んでいました:

PersonModel.find({ favoriteFoods : { $contains : "sushi" }, function(...) {...});

(私$containsはmongodb にはないことを知っています、解決策を知る前に私が見つけることを期待していたことを説明するだけです)

回答:


693

favouriteFoods文字列の単純な配列と同様に、そのフィールドを直接クエリするだけです。

PersonModel.find({ favouriteFoods: "sushi" }, ...);

ただし、スキーマで文字列配列を明示的にすることもお勧めします。

person = {
    name : String,
    favouriteFoods : [String]
}

関連ドキュメントはここにあります:https : //docs.mongodb.com/manual/tutorial/query-arrays/


19
場合にも動作しますfavouriteFoods:あるfavouriteFoods:[{type:Schema.Types.ObjectId, ref:'Food'}]
k88074

12
MySQLのようなRDBMSから来たMongoの新人として、そのようなソリューションがJOINと追加のテーブルを必要とせずに非常に簡単に機能することを知ると、なぜMongoをすぐに始めなかったのか不思議に思います。しかし、それはどちらのDBMSが他よりも優れていると言っているのではありません-それはあなたのユースケースに依存します。
Irvin Lim

9
間違えないでください。辞書のリストであっても、この方法でクエリできます。サンプル: PersonModel.find({ favouriteFoods.text: "sushi" }, ...); person = { name : String, favouriteFoods : [{text:String}] }
Aminah Nuraini、2015

3
少なくとも2つの文字列を含む配列を検索するとどうなりますか?
Aero Wang

151

$containsmongodbにはオペレーターがいません。

それが機能するので、JohnnyHKからの回答を使用できます。mongoが含むに最も近い例はです$in。これを使用すると、クエリは次のようになります。

PersonModel.find({ favouriteFoods: { "$in" : ["sushi"]} }, ...);

10
これは正しいです?mongodbは、$ inを使用するときに値の配列を期待していませんか?{name:{$ in:["Paul"、 "Dave"、 "Larry"、 "Adam"]}}のように?
Ludwig Magnusson 2013

38
えっ?これは不要です。$in複数のクエリ値があり、ドキュメントがそれらのいずれかに一致する必要がある場合に使用されます。逆の場合(この質問について)は、JohnnyHKの答えが正しいです。私は反対票を投じるつもりでしたが、この回答は、このページにたどり着いた他の人々に役立つかもしれません。
MalcolmOcean 2015

4
しかし、これは実際にいくつかの値でクエリを実行するのに役立ちました:D多くのおかげで!
Alexandre Bourlier 2016年

11
ありがとう。これは、私が実際に探していたものを、複数の値を検索する方法です:PersonModel.find({favouriteFoods: {"$in": ["sushi", "hotdog"]}})
totymedli

@MalcolmOceanは正しいです。$ in演算子は、配列をとして持つ逆の演算子です。フィールドの配列であることは疑問を約求めているものです。ただし、両方のフィールドと値が配列され、その後、この答えとJohnnyHKの両方を使用すると、中に$が必要なのかを意味し、関連しています。
tscizzle 2016年

88

$allこのような状況の方が適切だと思います。あなたが寿司を愛する人を探しているなら、あなたはそうします:

PersonModel.find({ favoriteFood : { $all : ["sushi"] }, ...})

次のように、検索をさらにフィルタリングしたい場合があります。

PersonModel.find({ favoriteFood : { $all : ["sushi", "bananas"] }, ...})

$inORや$allANDに似ています。これを確認してください:https : //docs.mongodb.com/manual/reference/operator/query/all/


申し訳ありませんが、これは私の質問に対する不正解です。私は完全に一致するものではなく、少なくとも指定された値を含む配列を探しています。
Ludwig Magnusson 2017年

18
これはあなたの質問に対する完全に有効な答えです!1つの値について、$ allまたは$ inを使用しても違いはありません。「sushi」、「bananas」などのいくつかの値がある場合、$ allは、favoriteFood配列で「sushi」および「bananas」を持つ人を探します。$ inを使用すると、「sushi」または「bananas」を持つ人を取得します"彼らの好きな食べ物の配列で。
浄土

ええ、$ containsはありませんが、$ allはそのようなものです
datdinhquoc

3
最良の答え。
Nikolay Tsenkov

65

配列にオブジェクトが含まれている場合favouriteFoods(たとえば、次のオブジェクトの配列の場合):

{
  name: 'Sushi',
  type: 'Japanese'
}

次のクエリを使用できます。

PersonModel.find({"favouriteFoods.name": "Sushi"});

2
これは簡単に最良の答えです。急いでいるときにはるかに使いやすくなります。
Uber Schnoz、

これが選択された答えです。MongoDBでネストされたドキュメントの配列のクエリを処理する場合は、これがその方法です。それが最も効率的であるかどうかはわかりませんが、それがあなたがやろうとしているすべてのことなら、これで十分です。
カイルL.

32

サブドキュメントの配列内にNULL要素を含むドキュメントを検索する必要がある場合は、このクエリがかなりうまくいくことがわかりました。

db.collection.find({"keyWithArray":{$elemMatch:{"$in":[null], "$exists":true}}})

このクエリはこの投稿から取得されました:null値のMongoDbクエリ配列

それは素晴らしい発見であり、私自身の最初のバージョンと間違ったバージョン(1つの要素を持つ配列でのみ正常に機能することが判明しました)よりもはるかにうまく機能します。

.find({
    'MyArrayOfSubDocuments': { $not: { $size: 0 } },
    'MyArrayOfSubDocuments._id': { $exists: false }
})

3

find()に同意することは、ユースケースで最も効果的です。それでも、集計フレームワークの$ matchがあります。これは、多数のエントリのクエリを容易にし、新しいファイルをグループ化および作成する場合に価値のある少数の結果を生成するためです。

  PersonModel.aggregate([
            { 
                 "$match": { 
                     $and : [{ 'favouriteFoods' : { $exists: true, $in: [ 'sushi']}}, ........ ]  }
             },
             { $project : {"_id": 0, "name" : 1} }
            ]);

mongodb 4.2で動作しない..返信してください
vimmi

どのようなエラーが発生していますか、詳しく教えてください。
アミテッシュ

3

lookup_food_arrayの場合は配列です。

match_stage["favoriteFoods"] = {'$elemMatch': {'$in': lookup_food_array}}

lookup_food_arrayの場合は文字列です。

match_stage["favoriteFoods"] = {'$elemMatch': lookup_food_string}

1

Loopback3の場合、指定されたすべての例は私にとっては機能しませんでした。しかし、それは私が必要とする正確な答えを理解するのに役立ちました。

{"where":{"arrayAttribute":{ "all" :[String]}}}


1
あなたは命の恩人です、ありがとう!それはどこに文書化されていて、見逃しましたか?リンクを投稿していただけますか?ありがとう。
user2078023

-3

JavaScriptで「contains」演算子のようなものを使用したい場合は、いつでも正規表現を使用できます...

例えば。名前として「Bartolomew」を持つ顧客を取得したいとします。

async function getBartolomew() {
    const custStartWith_Bart = await Customers.find({name: /^Bart/ }); // Starts with Bart
    const custEndWith_lomew = await Customers.find({name: /lomew$/ }); // Ends with lomew
    const custContains_rtol = await Customers.find({name: /.*rtol.*/ }); // Contains rtol

    console.log(custStartWith_Bart);
    console.log(custEndWith_lomew);
    console.log(custContains_rtol);
}

-26

私はこのトピックが古いことを知っていますが、同じ質問を不思議に思うかもしれない将来の人々にとって、別の信じられないほど非効率的な解決策は次のようにすることです:

PersonModel.find({$where : 'this.favouriteFoods.indexOf("sushi") != -1'});

これにより、MongoDBによるすべての最適化が回避されるため、本番用コードでは使用しないでください。


好奇心から、この方法でそれを行う利点はありますか?
Ludwig Magnusson 2014年

5
これは、受け入れられた回答に比べて信じられないほど非効率的です。それは、Mongoが受け入れられたような直接的な検索のために舞台裏で行うすべての最適化を回避します。
2014

1
これはまさに私の場合に必要な答えです!「ユーザー」ありがとう:)
Vasyl Boroviak
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.