Node.js异步嵌套的mysql查询

时间:2016-11-24 11:11:16

标签: mysql json node.js express async.js

要设置代码的方案,数据库会存储文档,并且每个文档都有可能将图像与其关联。

我一直在尝试编写一个查询数据库的路由,查找每个包含与其相关的图像的文档,将这些数据存储在JSON中,并在完成后返回到ajax请求,以便可以在页面上查看数据。我到目前为止最接近的是以下尝试(见代码)。

router.post('/advanced_image_search', userAuthenticated, function(req, res, next) {

  async.waterfall([
    // First function is to get each document which has an image related
    function getDocuments(callback){
      connection.query(`SELECT DISTINCT(Document.document_id), Document.doc_name, Document.doc_version_no, Document.doc_date_added
      FROM Document WHERE doc_type = 'image'`, function(err, results) {
        if (err) {
          callback(err, null);
          return;
        }

        // The Object containing the array where the data from the db needs to be stored
        var documents = {
          'docs': []
        };

        // foreach to iterate through each result found from the first db query (getDocuments)
        results.forEach(function(result) {

          // New object to store each document
          var document = {};

          document.entry = result;

          // This is the array where each image assciated with a document will be stored
          document.entry.images = [];
          // Push each document to the array (above)
          documents.docs.push(document);

          var doc_id = result.document_id;
        })
        // Returning the results as 'documents' to the next function
        callback(null, documents);
      })
    },
    function getImages(documents, callback){

      // Variable assignement to the array of documents
      var doc_array = documents.docs;

      // Foreach of the objects within document array
      async.forEachOf(doc_array, function(doc, key, callback){
        // Foreach object do the following series of functions
        async.waterfall([
          function handleImages(callback){

            // The id of the document to get the images for
            var doc_id = doc.entry.document_id;
            connection.query(`SELECT * FROM Image, Document WHERE Image.document_id = '${doc_id}' AND Image.document_id = Document.document_id`, function(err, rows) {
              if (err) {
                callback(err, null);
                return;
              }

              callback(null, rows);
            })
          },
          // Function below to push each image to the document.entry.images array
          //
          function pushImages(rows, callback){
            // If multiple images are found for that document, the loop iterates through each pushing to the images array
            for (var j = 0; j < rows.length; j++) {

              // Creating new object for each image found so the data can be stored within this object, then pushed into the images array
              var image = {
                'image_name': rows[j].image_name
              };

              doc.entry.images.push(image);
            }
            callback(null, doc_array);

          }

        ], function(err, doc_array){

          if (err) {
            console.log('Error in second waterfall callback:')
            callback(err);
            return;
          }
          console.log(doc.entry);
          // callback(null, doc_array);
        })
      }, function(err, doc_array){

        if (err) {
          callback(err);
          return;
        }

        callback(null, doc_array);

      });
      callback(null, doc_array);
    }
  ], function(err, doc_array) {

    if (err){
      console.log('Error is: '+err);
      return;
    }

    // The response that should return each document with each related image in the JSON
    res.send(doc_array);
  })

});

目前返回的结果是:

1:
{entry: {document_id: 1, doc_name: "DocumentNameHere", doc_version_no: 1,…}}
entry:
{document_id: 1, doc_name: "DocumentNameHere", doc_version_no: 1,…}
doc_date_added:"2016-10-24"
doc_name:"DocumentNameHere"
doc_version_no:1
document_id:1
images:[]

从上面可以看出,即使通过测试,图像阵列仍然是空的,正在找到图像(console.log)。

我希望有人能够帮助解决这个问题,因为我正在努力找到这个复杂的问题。

由于

1 个答案:

答案 0 :(得分:0)

这里有几个异步操作,每个操作都需要回调。见修改后的代码:

   router.post('/advanced_image_search', userAuthenticated, function(req, res, next) {

  var getDocuments = function(next) {
    // Function for getting documents from DB
    var query = `SELECT DISTINCT(Document.document_id), Document.doc_name, Document.doc_version_no, Document.doc_date_added FROM Document WHERE doc_type = 'image'`; // Set the query
    connection.query(query, function(err, results) {
        // Run the query async
        if(err) {
          // If err end execution
          next(err, null);
          return;
        }

        var documentList = []; // Array for holding docs
        for(var i=0; i<results.length; i++) {
          // Loop over results, construct the document and push to an array
          var documentEntry = results[i];
          var documentObject = {};
          documentObject.entry = documentEntry;
          documentObject.entry.images = [];
          documentObject.id = documentEntry.document_id;
          documentList.push(documentObject);
        }
        next(null, documents); // Pass to next async operation
      });
  };

  var getImages = function(documents, next) {
    // Function for getting images from documents
    var finalDocs = []; // Blank arry for final documents with images
    for (var i=0; i<documents.length; i++) {
      // Loop over each document and construct the query
      var id = documents[i].id;
      var query = `SELECT * FROM Image, Document WHERE Image.document_id = '${doc_id}' AND Image.document_id = Document.document_id`;

      connection.query(query, function(err, images) {
        // Execute the query async
         if(err) {
           // Throw error to callback
           next(err, null);
           return;
         }
         var processedDoc = processImages(documents[i], images); // Call a helper function to process all images into the document object
         finalDocs.push(processedDoc); // Push the processed doc

         if(i === documents.length) {
           // If there are no more documents move onto next async
           next(null, finalDocs);
         }
       });
    }
  };

  var processImages = function(doc, images) {
    for (var i=0; i< images.length; i++) {
      // Loop over each document image - construct object
      var image = {
        'image_name': rows[j].image_name
      };
      doc.entry.images.push(image); // Push image into document object
    }

    return doc; // Return processed doc
  };

  getDocuments(function(err, docs) {
    if(err) {
      // Your error handler
    }

    if(docs) {
      getImages(docs, function(err, finalDocs) {
        if(err) {
          // Your error handler
        }

        if(finalDocs) {
          console.log(finalDocs);
          res.status(200).json(finalDocs); // Send response
        }

      });
    }

  });
});
  1. 首先我们创建一个获取文档的函数 - 该函数接受一个回调作为其参数。我们运行查询并构建文档列表。然后我们通过执行回调
  2. 返回文档列表
  3. 接下来我们运行一个函数来获取每个文档的图像。此函数接受我们的文档列表和回调作为我们的参数。它检索每个文档的图像并调用辅助函数(sync)
  4. 我们的帮助函数将图像处理到每个文档中并返回已处理的文档。
  5. 然后,我们通过第二次回调返回一系列已处理的文档来完成我们的操作。
  6. 其他说明

    • 我们可以通过将此过程样式代码构造为包含的JSON对象
    • 来解决这个问题
    • 可以进一步清理文档末尾的函数执行嵌套
    • 我已经避免使用异步库,因为它有助于更​​好地理解回调模型
    • 事件发射器可用于展平回调 - 请参阅https://nodejs.org/dist/latest-v7.x/docs/api/events.html

    希望这有帮助

    迪伦