根据 mongodb 中第一个表的结果从第二个表加载数据

Posted

技术标签:

【中文标题】根据 mongodb 中第一个表的结果从第二个表加载数据【英文标题】:Loading data from a second table based on results from first table in mongo db 【发布时间】:2017-03-29 13:17:32 【问题描述】:

我正在尝试从 mongo db 加载和显示一些信息。我的网站在 node.js / express 上运行。

我有两个表格,第一个是调色板,我加载并显示所有表格,效果很好。但是对于每个调色板,我都有一个示例列表。我想遍历每个调色板,并获取该调色板的所有示例。

我肯定做错了什么,我认为这是因为 find() 方法是异步的,所以我的数据在提取额外数据之前就被发送了。但是我不能将渲染函数放在示例的回调中,因为它运行了多次。

php 中,我曾经能够从另一个表中提取数据并基于公共列将其连接到第一个表,但我不知道如何在此处执行此操作,这就是我尝试手动执行此操作的原因有一个循环。

/* GET palette database main page. */
router.get('/', function(req, res, next) 
  console.log('rendering test page');
  var Palette = require('../models/paletteDatabase');

  //load all palettes
  Palette.find(, function(err, palettes) 
    if (err) return next(err);

    var PaletteExamples = require('../models/paletteExamples');

    for (var i = 0; i < palettes.length; i++) 
      //split the colors into an array
      palettes[i].colorsArray = palettes[i].colors.split(',');

      PaletteExamples.find(paletteId: palettes[i]._id, function(err, result) 
        if (err) return next(err);

        palettes[i].examples=result;


      );
    

    res.render('palette-database', 
      title: 'Palette List',
      palettes: palettes,
      css: 'palette-db',
      js: 'palette-db'
    );

  );

);

【问题讨论】:

在此行之后发送您的回复palettes[i].examples=result; 我不能这样做,因为该行处于循环中,它会被发送多次(或者将在第一次之后发送) 那么删除你的for循环并在你的mongo请求中使用'in'查询呢? 【参考方案1】:

通过聚合框架中的 $lookup 运算符利用您的查询。这会对同一数据库中的另一个集合进行左外连接,以过滤来自“已连接”集合的文档以进行处理。

您可以使用此运算符运行聚合管道,如下所示:

/* GET palette database main page. */
router.get('/', function(req, res, next) 
    console.log('rendering test page');
    var Palette = require('../models/paletteDatabase');

    // load all palettes
    Palette.aggregate([
        
            "$lookup": 
                "from": "paletteExamples", // <-- collection name for examples
                "localField": "_id",
                "foreignField": "paletteId",
                "as": "examples"                
            
        
    ]).exec(function(err, docs)

        var palettes = docs.map(function(doc)
            doc["colorsArray"] = doc.colors.split(',');
            return doc;
        );

        res.render('palette-database', 
            title: 'Palette List',
            palettes: palettes,
            css: 'palette-db',
            js: 'palette-db'
        );
    );

);

在即将发布的 MongoDB 3.4 版本中,您可以通过使用 $split 操作符在 $project 管道中引入新字段来在服务器上进行字符串拆分如下:

// load all palettes
Palette.aggregate([
    
        "$lookup": 
            "from": "paletteExamples",
            "localField": "_id",
            "foreignField": "paletteId",
            "as": "examples"                
        
    ,
    
        "$project": 
            "examples": 1,
            "colorsArray":  "$split": ["$colors", ","] ,
            /* project other fields as necessary */
        
    
]).exec(function(err, palettes)    
    res.render('palette-database', 
        title: 'Palette List',
        palettes: palettes,
        css: 'palette-db',
        js: 'palette-db'
    );
);

【讨论】:

什么是“示例集合名称”,在哪里定义?我不太明白代码在做什么,但运行它会导致调色板未定义 我提供了指向 $lookup 运算符的文档链接,您可以参考。注释"collection name for examples" 用于将值替换为paletteExamples 集合的名称,即Mongoose 模型paletteExamples 的实际MongoDB 集合名称,您可以通过查询运行命令@ 的db 从mongo shell 中获取该名称987654335@ 由于某种原因,我无法通过控制台找到它,它必须在我的代码中的某个地方定义吗?是不是来自我的模型: var PaletteExample = mongoose.model('PaletteExample', paletteExampleSchema); 我认为 answer 应该有助于确定模型的集合名称。 谢谢,这很有帮助。我想我几乎已经解决了它,尽管它仍然返回一个空白数组作为示例。我必须升级到 mongo 3.2 才能使用查找,这很好。我也在数据库中找到了它,确保有其 example.paletteId 与palette._id 匹配的条目。我可以自己拉两个集合就好了。这是我的路由器:pastebin.com/ibtSVNQp /test2:成功输出示例,/test:成功获取调色板列表,每个都带有示例:[]。有什么想法吗?【参考方案2】:

这就是删除 for 循环的方法

var array = []; //your array
PaletteExamples.find('label':
    $in: array
   ,function(err, examples)

   

【讨论】:

以上是关于根据 mongodb 中第一个表的结果从第二个表加载数据的主要内容,如果未能解决你的问题,请参考以下文章

如何将两个表与 SQL Server 中第二个表中引用同一列的两列连接起来

LEFT JOIN,如果存在第二个表的结果,则添加到 PHP 中的数组

在多个连接条件下将数据从第二个表插入一个表

Microsoft SQL 查询 - 从第二个表返回最后一条记录

来自第二个表的 MySQL INNER JOIN (TOP10)

从第二个表存储过程mysql中仅通过其ID选择一个图像