【问题标题】:populate following users mongoose填充以下用户猫鼬
【发布时间】:2018-03-27 10:06:21
【问题描述】:

让我花时间解释从头到尾发生的事情。

序言

用户 a 关注了另外 10 个人。当用户 A 登录时,这 10 个人中的每个人的 X 个帖子都会被拉到视图中。

我不知道这是否是正确的做法,并且会欣赏更好的做法。但是,我想试一试,但它不起作用。

跟随模特

let mongoose = require('mongoose');
let Schema = mongoose.Schema;

let FollowSchema = new Schema({
  user: {
    type: Schema.Types.ObjectId,
    ref: 'User'
  },
  followers: [{
    type: Schema.Types.ObjectId,
    ref: 'Card'
  }],
  following: [{
    type: Schema.Types.ObjectId,
    ref: 'Card'
  }]
});

module.exports = mongoose.model('Follow', FollowSchema);

卡片模型

let mongoose = require('mongoose');
let Schema = mongoose.Schema;

let CardSchema = new Schema({
  title: String,
  content: String,
  createdById: {
    type: Schema.Types.ObjectId,
    ref: 'User'
  },
  createdBy: {
    type: String
  }
});

module.exports = mongoose.model('Card', CardSchema);

遵循逻辑

当用户A关注用户B时,做两件事:

  • 将 B 的 user_id 推送到字段 'following' 上的用户 A 文档(A 跟随 B)
  • 将 A 的 user_id 推送到字段“followers”上的用户 B 文档(B 后跟 A)

    router.post('/follow', utils.loginRequired, function(req, res) {
    const user_id = req.user._id;
    const follow = req.body.follow_id;
    
    let bulk = Follow.collection.initializeUnorderedBulkOp();
    
    bulk.find({ 'user': Types.ObjectId(user_id) }).upsert().updateOne({
        $addToSet: {
            following: Types.ObjectId(follow)
        }
    });
    
    bulk.find({ 'user': Types.ObjectId(follow) }).upsert().updateOne({
        $addToSet: {
            followers: Types.ObjectId(user_id)
        }
    })
    
    bulk.execute(function(err, doc) {
        if (err) {
            return res.json({
                'state': false,
                'msg': err
            })
        }
        res.json({
            'state': true,
            'msg': 'Followed'
        })
    })
    

    })

实际数据库值

> db.follows.find().pretty()
{
    "_id" : ObjectId("59e3e27dace1f14e0a70862d"),
    "user" : ObjectId("59e2194177cae833894c9956"),
    "following" : [
        ObjectId("59e3e618ace1f14e0a708713")
    ]
}
{
    "_id" : ObjectId("59e3e27dace1f14e0a70862e"),
    "user" : ObjectId("59e13b2dca5652efc4ca2cf5"),
    "followers" : [
        ObjectId("59e2194177cae833894c9956"),
        ObjectId("59e13b2d27cfed535928c0e7"),
        ObjectId("59e3e617149f0a3f1281e849")
    ]
}
{
    "_id" : ObjectId("59e3e71face1f14e0a708770"),
    "user" : ObjectId("59e13b2d27cfed535928c0e7"),
    "following" : [
        ObjectId("59e3e618ace1f14e0a708713"),
        ObjectId("59e13b2dca5652efc4ca2cf5"),
        ObjectId("59e21942ca5652efc4ca30ab")
    ]
}
{
    "_id" : ObjectId("59e3e71face1f14e0a708771"),
    "user" : ObjectId("59e3e618ace1f14e0a708713"),
    "followers" : [
        ObjectId("59e13b2d27cfed535928c0e7"),
        ObjectId("59e2194177cae833894c9956")
    ]
}
{
    "_id" : ObjectId("59e3e72bace1f14e0a708779"),
    "user" : ObjectId("59e21942ca5652efc4ca30ab"),
    "followers" : [
        ObjectId("59e13b2d27cfed535928c0e7"),
        ObjectId("59e2194177cae833894c9956"),
        ObjectId("59e3e617149f0a3f1281e849")
    ]
}
{
    "_id" : ObjectId("59f0eef155ee5a5897e1a66d"),
    "user" : ObjectId("59e3e617149f0a3f1281e849"),
    "following" : [
        ObjectId("59e21942ca5652efc4ca30ab"),
        ObjectId("59e13b2dca5652efc4ca2cf5")
    ]
}
> 

有了上面的数据库结果,这是我的查询:

查询

router.get('/follow/list', utils.loginRequired, function(req, res) {
    const user_id = req.user._id;

    Follow.findOne({ 'user': Types.ObjectId(user_id) })
      .populate('following')
      .exec(function(err, doc) {
          if (err) {
              return res.json({
                  'state': false,
                  'msg': err
              })
          };

          console.log(doc.username);

          res.json({
              'state': true,
              'msg': 'Follow list',
              'doc': doc
          })
      })
});

通过上述查询,根据我对 Mongoose 填充的一点了解,我希望从 following 数组中的每个用户那里获得卡片。

我的理解和期望可能是错误的,但是有了这样的最终目标,这种填充方法可以吗?还是我试图解决人口聚合任务?

更新:

感谢您的回答。非常接近,但followingCards 数组仍然不包含任何结果。这是我当前Follow 模型的内容:

> db.follows.find().pretty()
{
    "_id" : ObjectId("59f24c0555ee5a5897e1b23d"),
    "user" : ObjectId("59f24bda1d048d1edad4bda8"),
    "following" : [
        ObjectId("59f24b3a55ee5a5897e1b1ec"),
        ObjectId("59f24bda55ee5a5897e1b22c")
    ]
}
{
    "_id" : ObjectId("59f24c0555ee5a5897e1b23e"),
    "user" : ObjectId("59f24b3a55ee5a5897e1b1ec"),
    "followers" : [
        ObjectId("59f24bda1d048d1edad4bda8")
    ]
}
{
    "_id" : ObjectId("59f24c8855ee5a5897e1b292"),
    "user" : ObjectId("59f24bda55ee5a5897e1b22c"),
    "followers" : [
        ObjectId("59f24bda1d048d1edad4bda8")
    ]
}
>

这是我从Card Model 获得的所有当前内容:

> db.cards.find().pretty()
{
    "_id" : ObjectId("59f24bc01d048d1edad4bda6"),
    "title" : "A day or two with Hubtel's HTTP API",
    "content" : "a day or two",
    "external" : "",
    "slug" : "a-day-or-two-with-hubtels-http-api-df77056d",
    "createdBy" : "seanmavley",
    "createdById" : ObjectId("59f24b391d048d1edad4bda5"),
    "createdAt" : ISODate("2017-10-26T20:55:28.293Z"),
    "__v" : 0
}
{
    "_id" : ObjectId("59f24c5f1d048d1edad4bda9"),
    "title" : "US couple stole goods worth $1.2m from Amazon",
    "content" : "for what",
    "external" : "https://bbc.com",
    "slug" : "us-couple-stole-goods-worth-dollar12m-from-amazon-49b0a524",
    "createdBy" : "nkansahrexford",
    "createdById" : ObjectId("59f24bda1d048d1edad4bda8"),
    "createdAt" : ISODate("2017-10-26T20:58:07.793Z"),
    "__v" : 0
}

使用您 (@Veeram) 中的填充虚拟示例,我得到的响应如下:

{"state":true,"msg":"Follow list","doc":{"_id":"59f24c0555ee5a5897e1b23d","user":"59f24bda1d048d1edad4bda8","following":["59f24b3a55ee5a5897e1b1ec","59f24bda55ee5a5897e1b22c"],"followers":[],"id":"59f24c0555ee5a5897e1b23d","followingCards":[]}}

followingCards 数组为空。

另一方面,使用$lookup 查询只返回[]

我可能错过了什么?

【问题讨论】:

  • 用你的模式编辑你的问题。
  • @JohnnyHK 好的。会的。
  • populate 仅在保存前将 refs 推送到 Follow.following 时才有效!

标签: mongodb mongoose mongoose-populate


【解决方案1】:

您可以在聚合管道中使用虚拟填充或$lookup 运算符。

使用虚拟填充

FollowSchema.virtual('followingCards', {
    ref: 'Card',
    localField: 'following',
    foreignField: 'createdById'
});

Follow.findOne({ 
   'user': Types.ObjectId(user_id) })
   .populate('followingCards')
   .exec(function(err, doc) {      
      console.log(JSON.stringify(doc));
});

使用$lookup聚合

Follow.aggregate([
  {
    "$match": {
      "user": Types.ObjectId(user_id) 
    }
  },
  {
    "$lookup": {
      "from": "cards",
      "localField": "following",
      "foreignField": "createdById",
      "as": "followingCards"
    }
  }
]).exec(function (err, doc) {
     console.log(JSON.stringify(doc));
})

【讨论】:

  • 感谢您的回复。试过你的方法。 followingCards 数组是响应对象的一部分,但是该数组包含一个空列表。请查看当前数据库中实际值的更新问题。
  • Np。您可以在文件顶部添加 mongoose.set('debug', true); 以查看发送到 mongodb 的查询吗?顺便说一句,我已修复查找以包含正确的集合名称cards。您是否也可以尝试不使用匹配阶段的查找聚合来检查它是否有效,然后您可以将其放回原处?
  • follows 集合中的following 数组字段值在cards 集合中没有匹配的createdById。尝试使用 followers 字段代替您提供的数据,您可以适当地调整答案。
【解决方案2】:
var mongoose = require('mongoose'), Schema = mongoose.Schema

var eventSchema = Schema({
title     : String,
location  : String,
startDate : Date,
endDate   : Date
});

var personSchema = Schema({
firstname: String,
lastname: String,
email: String,
dob: Date,
city: String,
eventsAttended: [{ type: Schema.Types.ObjectId, ref: 'Event' }]
});

var Event  = mongoose.model('Event', eventSchema);
var Person = mongoose.model('Person', personSchema);

为了展示如何使用填充,首先创建一个人对象,

   aaron = new Person({firstname: 'Aaron'}) and an event object, 
   event1 = new Event({title: 'Hackathon', location: 'foo'}):

   aaron.eventsAttended.push(event1);
   aaron.save(callback); 

然后,当您进行查询时,您可以像这样填充引用:

 Person
.findOne({ firstname: 'Aaron' })
.populate('eventsAttended') .exec(function(err, person) {
if (err) return handleError(err);
console.log(person);
 });

// 仅当我们将 refs 推送到 person.eventsAttended 时才有效

【讨论】:

    【解决方案3】:

    注意:将 Activity.find 更改为 Card.find

    const { ObjectID } = require("mongodb");
    // import Follow and Activity(Card) schema
    
    const userId = req.tokenData.userId; // edit this too...
    Follow.aggregate([
      {
        $match: {
          user: ObjectID(userId)
        }
      }
    ])
    .then(data => {
      // console.log(data)
      var dataUsers = data[0].following.map(function(item) {
        return item._id;
      });
      // console.log(dataUsers)
      Activity.find(
        { createdById: { $in: dataUsers } },
        {
          _id: 1,
          title: 1,
          content: 1,
          createdBy: 1,
          creatorAvatar: 1,
          activityType: 1,
          createdAt: 1
        }
      )
        // .sort({createdAt:-1)
        .then(posts => res.send({ posts }));
    });
    

    【讨论】:

      猜你喜欢
      • 2015-07-13
      • 2016-10-10
      • 2019-09-16
      • 2015-07-13
      • 2020-01-17
      • 2021-05-03
      • 2021-01-09
      • 2018-06-01
      相关资源
      最近更新 更多