【问题标题】:Mongoose find by a subdocument's valueMongoose 按子文档的值查找
【发布时间】:2021-02-11 23:53:31
【问题描述】:

我有 2 个架构

const schema = Schema({
    headLine: {
        type: String,
        required: false
    },
    availableDays: [{
        type: Schema.Types.ObjectId,
        ref: AvailableDay
    }]
}, {collection: 'providers', timestamps: true});

module.exports = mongoose.model("Provider", schema);

const schema = Schema({
    day: {
        type: String,
        enum: ['Mondays','Tuesdays','Wednesdays','Thursdays','Fridays','Saturdays','Sundays']
    },
    timeFrom: String,
    timeTo: String
}, {collection: 'availableDays', timestamps: true});

module.exports = mongoose.model("AvailableDay", schema);

然后在路由中我调用这样的存储库

router.get('/', async (req, res) => {


    const match = {};
    const sort  = {};
    const options  = {};


    // Arrange sort
    if(req.query.sortBy){
        const sortArray = JSON.parse(req.query.sortBy);
        sortArray.map(e => sort[e[0]] = e[1] && e[1] === 'desc' ? -1 : 1);
        options['sort'] = sort
    }

    // Get the pagination: limit how many, skip where it starts
    if(req.query.limit) {
        options['limit'] = parseInt(req.query.limit);
    }
    if(req.query.skip) {
        options['skip'] = parseInt(req.query.skip);
    }

    const docs = await ProviderRepository.findBy(match, {}, options);

    res.status(200).json(docs)

});

所以我在这里需要的是过滤提供者的可用日星期一并返回文档并计算总文档以进行分页。我正在做这样的事情但没有成功

const findBy = async (params, projection = "", options = {}, callback) => {
    const data = () => {
        Provider.find(params, projection, options)
            .populate([{path: 'user', match: {gender: 'F'}}]).exec((error, e) => {
            if (error) {
                console.log('error:', error)
                return {error: error}; // returns error in json
            }
            return e.filter(i => i.user);
        });
    };


        const total = await Provider.countDocuments(params).exec();
    return {data(), total}

}

提前致谢

【问题讨论】:

    标签: javascript node.js mongodb mongoose


    【解决方案1】:

    使用mongoose-aggregate-paginate-v2 并更新您的架构。如果您使用该软件包,则必须将您的查询从 populate 转换为 aggregate 样式。

    第 1 步:更新架构。示例架构:

    const mongoose = require('mongoose');
    const mongoosePaginate = require('mongoose-aggregate-paginate-v2');
    const Schema = mongoose.Schema;
    
    let definition = {
      headLine: {
        type: String,
        required: false
      },
      availableDays: [{
        type: Schema.Types.ObjectId,
        ref: AvailableDay
      }]
    };
    
    let options = {
      collection: 'providers'
    };
    
    let providerSchema = new Schema(definition, options);
    providerSchema.plugin(mongoosePaginate);
    
    module.exports = mongoose.model('providers', providerSchema);
    
    

    第 2 步:更新控制器。控制器中的示例代码:

    router.get('/', async (req, res) => {
      const match = {}
    
      const sort = {
        // Fill it based on your sort logic.
      }
    
      const paginateOptions = {
        page: req.query.page,       // Page number like: 1, 2, 3...
        limit: req.query.limit      // Limit like: 10, 15, 20...
      };
    
      ProviderRepository
        .findBy(match, {}, sort, paginateOptions)
        .then(() => {
          res.status(200).json(docs)
        })
        .catch(() => {
          res.status(HTTP_ERROR_CODE).json({ "error": "Your error message" })
        })
    });
    

    第 3 步:更新管理器。管理器中的示例代码:

    const findBy = (match, projection, sort, paginateOptions) => {
      if (!paginateOptions) {
        paginateOptions = {
          pagination: false
        };
      }
    
      let providerAggregate = providerSchema.aggregate([
        {
          $lookup: {
            from: "availableDays",
            let: { days: "$availableDays" },
            pipeline: [
              {
                $match: {
                  $expr: { 
                    $in: ["$$availableDays", "$day"]
                  }
                }
              }
            ],
            as: "availableDays"
          }
        },
        {
          $lookup: {
            from: "users",                  // I dont know the collection name
            let: { user_id: "$user" }
            pipeline: [
              {
                $match: {
                  "gender": 'F',
                  $expr: { 
                    $eq: ["$_id", "$$user_id"]
                  }
                }
              }
            ],
            as: "users"
          }
        }
        { $sort: sort }
      ]);
    
      return providerSchema
        .aggregatePaginate(providerAggregate, paginateOptions)
        .then(res => {
          return res;
        })
        .catch(err => {
          throw err;
        });
    };
    

    【讨论】:

    • 嗨,谢谢你的回答,很完整,但是我应该在条件和项目中发送什么?
    • 我怎样才能在那里填充?
    • 需要在条件和项目中放入什么取决于您的要求。它是可选的,如果不需要,您可以跳过它们。 populate 是 mongoose 库提供的聚合的替代方案,它不是 MongoDB 原生的。执行另一个 $lookup 操作来填充用户数据。我会更新答案。请查看stackoverflow.com/questions/55575806/…
    猜你喜欢
    • 2013-05-26
    • 2017-04-15
    • 1970-01-01
    • 2014-11-27
    • 2015-08-24
    • 2023-03-20
    • 2018-06-27
    • 1970-01-01
    相关资源
    最近更新 更多