9

私は MongoDB を学ぼうとしていますが、今のところ素晴らしいです。しかし、私は状況に遭遇し、それを解決する方法がよくわかりません。うまくいけば、誰かが私を助けてくれます。

(全体の)配列値がクエリ内にあるというレコードを取得したかったのです。例えば:

レコード 1 :

{"name" : "Mango Shake", 
 "ingredients" : [{"type" : "fruit", "name" : "mango"},
                  {"type" : "milk", "name" : "soy milk"}]}

レコード 2 :

{"name" : "Mango Banana Shake", 
 "ingredients" : [{"type" : "fruit", "name" : "mango"},
                  {"type" : "milk", "name" : "soy milk"},
                  {"type" : "fruit", "name" : "banana"}]}

レコード 3:

{"name" : "Milk Shake", 
 "ingredients" : [{"type" : "milk", "name" : "soy milk"}]}

次に、次のようなクエリがあります

{"ingredients" : {$all : [{"type" : "fruit", "name" : "mango"},
                          {"type" : "milk", "name" : "soy milk"},
                          {"type" : "fruit", "name" : "strawberry"}]}}

「マンゴー」豆乳」「いちご」があるから。だから私は自分ができるシェイクを知りたかった. クエリに余分なものを含めることができないため、明らかにこれは何も返しません。使えば元に$in戻りますが、バナナがないのでマンゴーバナナシェイクはできません..

だから私が必要なのは最初と最後のものだけです。何か案が?感謝します :)

4

8 に答える 8

0

検索パラメーターとして JavaScript 関数を使用できます。ただし、MapReduce は、スケーラビリティと、実行されるコードにユーザー入力を挿入することに伴う一般的な不安により、全体的にはるかに洗練されたソリューションになると思います。

作成されるクエリの例を次に示します。基本的に、アイテムの成分をフィルタリングし、フィルタリングされたリストが元の成分リストと同じ長さであることを確認します。

db.shakes.find(function() {

  // Implant your query JSON object here
  var query_obj = [{"type" : "fruit", "name" : "mango"},
                   {"type" : "milk", "name" : "soy milk"},
                   {"type" : "fruit", "name" : "strawberry"}];  
  return this.ingredients.filter(function(ingredient) {
    var has_ingredients = false;
    query_obj.forEach(function(query) {
      has_ingredients |= (query.type == ingredient.type && query.name == ingredient.name);
    });
    return has_ingredients;
  }).length === this.ingredients.length;
})
于 2013-03-12T19:53:45.647 に答える
0

ドット表記を使用して配列の特定の要素にアクセスし、各要素が$in使用可能な成分リストであることを確認できます。$andクエリを実行するドキュメント内の各要素に対してクエリを作成することもできますが、もちろん機能しません。各レシピの材料リストに要素がいくつあるかわかりません。

この問題の 1 つの解決策は、固定サイズ (おそらく 3 要素) の配列を各ドキュメントに追加することです。この配列には、レシピから n 個の最も一般的でない材料を入れて、パディング (必要に応じて配列を埋めるために繰り返します) します。これで、その配列の各要素を使用$andしてクエリを実行できます。$inこれにより、可能な「可能性のある」すべてのレシピが見つかります。また、最も一般的でない材料を保存したため、作成できないレシピをフィルター処理して適切に除外する必要があります。その後、クライアント側で最終フィルターを実行できます。

データの別の表現を追加することが、このようなトリッキーなクエリの問題を解決する良い方法になる場合があります。また、サーバー側とクライアント側のフィルタリングの組み合わせが適切な場合もあります。

于 2013-01-19T20:18:49.607 に答える
0

必要に応じて Map reduce を使用するか、各成分に対して 1 つの条件で $and を使用できます。

http://docs.mongodb.org/manual/reference/operator/and/

同様のクエリのニーズに $and before を使用しました。残念ながら、どちらの場合も、クエリを実行するたびにすべてのレシピ ドキュメントをチェックする必要があり、コレクションが大きくなるとパフォーマンスに深刻な影響を与えます。

これは、リレーショナル データベースでより適切に処理できる場合があります。少なくとも、それらを使用するレシピ ID へのマップを持つ材料の個別のクエリ可能なインデックスを保持することを検討する必要があります。次に、持っている材料だけを取得し、コードでレシピの交差を取得できます。繰り返しますが、これは実際にはリレーショナル データベースで実行できることなので、ここでは単純にこれを選択する方が適切かもしれません。

于 2013-01-19T18:05:02.970 に答える
0

operatorの使用に関する警告に$where問題がないと仮定すると、それをArray.prototype.someおよびArray.prototype.everyと組み合わせて使用​​して、目的の結果を得ることができます。

これは JavaScript 固有のソリューションのように見えますが、そうではありません。JavaScript は Mongo (V8) に直接注入されます。すべての言語ドライバーがそれをサポートする必要があります。少なくともPHP が.

このコードをMongo REPLに直接貼り付けると、期待どおりの結果が得られるはずです (木をたたきます)。

もしあなたのミルクセーキデータベースがあなたの能力を超えて拡張する可能性を秘めている$whereなら、Aggregation Frameworkはあなたの味方です。

var query = {
    "$where": function() {
        var myIngredients = [
            {"type" : "fruit", "name" : "mango"},
            {"type" : "milk", "name" : "soy milk"},
            {"type" : "fruit", "name" : "strawberry"}
        ];
        return obj.ingredients.every(function(milkShakeIngredient){
            return myIngredients.some(function(myIngredient){
                return ( milkShakeIngredient.name === myIngredient.name &&  milkShakeIngredient.type === myIngredient.type );
            });
        });
    }
};

db.milkShakes.find(query);
于 2014-12-12T21:15:06.647 に答える
0

すべての材料の既知のセットがある場合に、いくつかの新しいアイデアをもたらすために. たとえば、可能な成分はわずか 5 です。

["mango","soy milk", "strawberry", "banana", "pineapple"]

そして、あなたはバナナもパイナップルも持っていません

1 つのオプションは、持っていない成分を照会することです。

{"ingredients" : {$nin : [{"type" : "fruit", "name" : "banana"},
                          {"type" : "fruit", "name" : "pineapple"}]}}

これは、あなたが持っていない成分を持っていないすべてのドキュメントを返します。つまり、実際に持っている成分を含むレシートです。

于 2014-11-05T17:58:34.910 に答える
0

find でこれを行う方法が思いつきませんでした。しかし、 mapReduceでそれを行うことができます。

マップ関数は、現在調査中のドキュメントの構成要素を反復処理し、すべてのフィールドが構成要素である場合にのみ発行します。これには reduce 関数は必要ないため、出力される値のキーは、drink ドキュメントの _id にする必要があります。

キーが一意の場合は、reduce 関数を呼び出してはなりません (reduce 関数は、同じキーに対して複数の値が発行されたときに何が起こるかを判断するために使用されます)。reduce 関数を単に省略できるとは思えないので、values 配列の最初の要素を返すだけの関数を作成する必要があります。

于 2012-10-15T09:11:36.650 に答える