2016-11-01 5 views
0

Ooof。あなたが近づいていることを知っている当時のことは一度もありましたが、それを得ることはできません。ノード内で可変数のmongoクエリを実行し、単一結果を返します

私はハングマンパズルソルバーを書いています。これはmongo dbでバックエンドされたnode/hapiで書かれたサービスで実行されています。

だから私は機能を持っている:

?O?N? ?O ?H? ?TO?? 

とalreadyCalledは単純であること:?

solvePuzzle(puzzle, alreadyCalled); 

はargsがそうのように、解決リテラルとして文字、およびSなど未解決で、パズルそのものです呼び出されたが正しくない文字のリスト。いくつかのmuckingについては、各単語に対してRegExが作成され、mongoに格納されている単語リストに照会する関数に送信されます。

すべてが機能しています。ダミーワードリストを単純な配列として作成すると、すべて正常に動作し、一致するリストが取得されます。

戻り形式はそうのようなオブジェクトの配列である:実際の問題のように

matches[0][?O?N?] = ['GOING', 'DOING', 'BOING']; 

を(可能な解決策を表示するとき、私は単語の順序を保存する配列のインデックスを使用します)。パズル全体を単語に分割し、forループを実行して、それぞれについてmongoクエリーを実行する関数を呼び出します。問題は、関数呼び出しは、クエリが実際に実行される前に戻っているようです。中に散在しているコンソールログは、この理論を裏付けているようです。

私は、クエリ関数を約束してもらうことを試みましたが、それはさらに水を濁らせるだけでした。私はを閉じているように感じるが、私はうんざりだ。ここに私の元の非約束のコードだった:

function solvePuzzle(puzzle, called) { 
    // first build the exclusion match pattern 
    //console.log('solvePuzzle: building match pattern'); 
    var x = buildMatchPattern(puzzle, called); 
    // split the puzzle into words 
    //console.log('solvePuzzle: tokenizing puzzle'); 
    var words = tokenize(puzzle.toUpperCase()); 
    //console.log('solvePuzzle:', words); 
    var results = []; 

    for(var i = 0; i < words.length; i++) { 
     console.log('solvePuzzle: matching ' + words[i]); 
     results[i] = {}; 
     results[i][words[i]] = matchWord(words[i], x); 
    } 
    console.log('solvePuzzle: matches: ', results); 
    return results; 
} 

function matchWord(word, exclude) { 
    var pattern = '^'; 
    var letters = word.toUpperCase().split(''); 
    var matches = new Array(); 
    var query = {}; 

    //console.log('matchWord:', letters); 

    for(var i = 0; i < letters.length; i++) { 
     if(letters[i] !== '?') { 
      pattern += letters[i]; 
     } 
     else { 
      pattern += exclude; 
     } 
    } 

    pattern += '$'; 
    var re = new RegExp(pattern); 
    //console.log('matchWord:', re); 

    query.word = {"$regex" : re, "$options": "i"}; 
    //console.log("matchWord query:", JSON.stringify(query)); 
    db.wordlist.find(query, function (err, words) { 
     if(err) { 
      console.error('error:', err); 
     } 
     for(let i = 0; i < words.length; i++) { 
      if(words[i] !== null) { 
       console.log('loop:', words[i].word); 
       matches.push(words[i].word); 
      } 
     } 
     console.log('matchWord:', matches.length); 
     if(matches.length < 1) { 
      console.log('matchWord: found no matches'); 
      matches.push('No Matches Found'); 
     } 

     return matches; 
    }); 
} 

は、だから私のコンソール出力は、基本的だった:

solvePuzzle: matching ?O?N? 
solvePuzzle: matches: []  <---- problem 
loop: 'going' 
loop: 'doing' 
etc etc. 
. 
. 
matchWord: 5 (number of matches found); 

あなたが見ることができるように実際のクエリが実行されている前に、matchWordへの呼び出しが戻っています。だから私はmongoに裏打ちされたhapiサービスを一度もやっていない。どのようにしてこのコードを構造化して、すべての単語をループし、それぞれに対してmongoをクエリし、結果として単一の配列を返しますか?

TIA。

+0

は私の更新を参照してください! – felix

答えて

0

ノードでは、データベース呼び出しは非同期なので、returnをこのように使用することはできません。 あなたは、このコードは動作するはずの約束(Node.jsの中にネイティブ)

を使用する必要があります。

function solvePuzzle(puzzle, called) { 
     var results = []; 
     // first build the exclusion match pattern 
     var x = buildMatchPattern(puzzle, called); 
     // split the puzzle into words 
     var words = tokenize(puzzle.toUpperCase()); 
     // an array to store the words index 
     var indexes = Array.apply(null, { 
      length: words.length 
     }).map(Number.call, Number); // looks like [1, 2, 3, 4, ...] 
     // create a Promise for each word in words 
     var promises = indexes.map(function(index) { 
      return new Promise(function(resolve, reject) { 
       console.log('solvePuzzle: matching ' + words[index]); 
       results[index] = {}; 
       var pattern = '^'; 
       var letters = words[index].toUpperCase().split(''); 
       var matches = new Array(); 
       var query = {}; 

       for (var i = 0; i < letters.length; i++) { 
        if (letters[i] !== '?') { 
         pattern += letters[i]; 
        } else { 
         pattern += exclude; 
        } 
       } 
       pattern += '$'; 
       var re = new RegExp(pattern); 

       query.word = { 
        "$regex": re, 
        "$options": "i" 
       }; 
       db.wordlist.find(query, function(err, wordsRes) { 
        if (err) { 
         console.error('error:', err); 
         reject(err); // if request failed, promise doesn't resolve 
        } 
        for (let i = 0; i < wordsRes.length; i++) { 
         if (wordsRes[i] !== null) { 
          console.log('loop:', wordsRes[i].word); 
          matches.push(wordsRes[i].word); 
         } 
        } 
        console.log('matchWord:', matches.length); 
        if (matches.length < 1) { 
         console.log('matchWord: found no matches'); 
         matches.push('No Matches Found'); 
        } 
        results[index][words[index]] = matches; 
        resolve(); // request successfull 
       }); 
      }); 
     }); 
     // when all promise has resolved, then return the results 
     Promise.all(promises).then(function() { 
      console.log('solvePuzzle: matches: ', results); 
      return results; 
     }); 
    } 
+0

悲しいことに、これは動作しません。私はVSコードでデバッガを使用して、戻り値にブレークポイントを設定します。 solvePuzzleの行に戻ってくると、すべてのマッチがコンソールに表示されます。したがって、「CK?Y?A ???」を使用するクライアント(この場合は郵便配達員)は、入力として3つの空のオブジェクトの配列をレスポンスとして取得します。 – MonkRocker

+0

ああ私はsolvePuzzle、私の悪いの戻りを忘れました。あなたはここで約束を使用する必要があります。私はちょっとして答えを更新します。 – felix

+0

hapiのルートハンドラによって呼び出されていたので、やっぱりやってみました。コールバックを渡して解決してください。いずれにしても - これに感謝します。私は約束が解決策になることを知っていた、私はちょうどそれを構造化する方法を正確に把握できませんでした。 – MonkRocker

関連する問題