【问题标题】:Mongoose field match populate猫鼬字段匹配填充
【发布时间】:2014-01-08 14:38:19
【问题描述】:

我在如何最好地在 mongoose 中实现此连接/查询时遇到了一些麻烦。

var mongoose = require('mongoose');
var addressSchema = new mongoose.Schema{
                    rank: Number, 
                    address: String,
                    tag_name: String,
                    tag_url: String};

var tagSchema = new mongoose.Schema{
                    address: String, 
                    name: String,
                    url: String};

我保存了一堆地址和一堆标签。有些地址有标签,大多数没有。我经常分别更新地址和标签。我想要做的是查询一些特定的地址并将它们作为一个数组返回,其中填充了标签字段(地址标签字段在数据库中是空白的)。

例如,我想在不为每个地址进行数据库查询的情况下执行此操作(示例中为 101 个数据库查询)。我不确定 $match 或 $in 或 populate 是否是我正在寻找的。以下代码未经测试,可能无法正常工作,但它应该让您了解我正在尝试做什么。

var db = require('../config/dbschema');

// find an array of addresses
db.addressModel.find({ rank: { $lte: 100 } }, function(err, addresses) {
  // now fill in the tag fields and print
  addTagField(0, addresses);
});

// recursive function to fill in tag fields
// address tag name and tag url fields are blank in the database
function addTagField(n, addresses) {
  if(n < addresses.length) {
    db.tagModel.find( { address: addresses[n].address }, function(err, tag) {
      // if find a tag with this address, fill in the fields
      // otherwise leave blank and check next address in array
      if(tag) {
        addresses[n].tag_name = tag.name;
        addresses[n].tag_url = tag.url;
      }
      addTagField(n+1, addresses);
    });
  } else {
    console.log(addresses);
  }
}

http://mongoosejs.com/docs/api.html#aggregate_Aggregate-match http://mongoosejs.com/docs/api.html#query_Query-in http://mongoosejs.com/docs/api.html#document_Document-populate

我想用更少的数据库查询完成上述操作。

【问题讨论】:

  • 我不遵循你想要做的事情。 $match 仅用于聚合。 $in 是当您希望根据您为特定字段匹配的列表匹配多个文档时。
  • 由于它们位于两个不同的集合中,您要么必须收集地址并查询标签,要么使用 mapReduce。 mongoosejs.com/docs/api.html#model_Model.mapReduce

标签: node.js mongodb mongoose


【解决方案1】:

我不想嵌入文档。这就是我想出的。

db.addressModel.find({ rank: { $lte: 100 } }, function(err, addresses) {
  if(err) return res.send(400);
  if(!addresses) return res.send(404);
  var addrOnlyAry = addresses.map(function(val, idx) { return val.address; });
  db.tagModel.find( { address: { $in: addrOnlyAry } }, {}, function(err, tags) {
    if(err) return res.send(400);
    if(tags.length > 0) addresses = setTagFields(addresses, tags);
    return res.json(addresses);
  }
}

function setTagFields(addresses, tags) {
  for(var i=0; i < tags.length; i++) {
    for(var j=0; j < addresses.length; j++) {
      if(addresses[j].address === tags[i].address) {
        addresses[j].tag_name = tags[i].tag;
        addresses[j].tag_url = tags[i].url;
        break;
      }
    }
  }
  return addresses;
}

【讨论】:

    【解决方案2】:

    您的主要问题是您没有利用 Mongoose 的关系映射。稍微改变一下你的模式,你的问题就会很容易解决。你可以这样做:

    var tagSchema = new Schema({
        name: String,
        url: String,
    })
    
    var addressSchema = new Schema ({
        rank: Number, 
        address: String,
        tags: [tagSchema],
    })
    
    addressModel.find({rank: {$lte: 100}}, function(err, addresses) {
        ...
    })
    

    或者这个:

    var tagSchema = new Schema({
        name: String,
        url: String,
    })
    
    var addressSchema = new Schema ({
        rank: Number, 
        address: String,
        tags: [{type: ObjectId, ref: 'Tag'}],
    })
    
    addressModel
        .find({rank: {$lte: 100}})
        .populate('tags', 'name url')
        .exec(function(err, addresses) {
            ...
        })
    

    【讨论】:

    • 这不太正确,因为tags 应该是一个引用数组(不是嵌入式文档),populate 才能工作。
    • 其实你是对的,我的错,你可以跳过所有与这个模式一起填充,我会更新答案。
    猜你喜欢
    • 2021-05-06
    • 2019-07-22
    • 1970-01-01
    • 2015-07-13
    • 2016-10-10
    • 2019-05-04
    • 2019-09-16
    • 2021-01-25
    相关资源
    最近更新 更多