【问题标题】:$lookup returns an empty array mongoose$lookup 返回一个空数组 mongoose
【发布时间】:2020-06-18 19:02:36
【问题描述】:

我正在使用带有 $lookup 函数的以下代码。

        postSchemaModel.aggregate([{
            "$geoNear": {
                "near": { "type": "Point", "coordinates": [6.7336665, 79.8994071], "Typology": "post" },
                "distanceField": "dist.calculated",
                "maxDistance": 5000,
                "includeLocs": "dist.location",
                "spherical": true
            }
        },
        { "$limit": limit },
        { "$skip": startIndex },
        { "$sort": { "createdAt": -1 } },
        {
            "$lookup": {
                "from": userSchemaModel.collection.name,
                "localField": "user_id",
                "foreignField": "_id",
                "as": "user_id"
            }
        },
        {
            "$project": {
                "post_data": 1,
                "likes": 1,
                "commentsCount": 1,
                "post_img": 1,
                "isUserLiked": 1,
                "usersLiked": 1,
                'exp_date': 1,
                "has_img": 1,
                "user_id": "$user_id",
                "typology": 1,
                "geometry": 1,
                "category": 1,
                "created": 1,
                "createdAt": 1,
                "updatedAt": 1,
            }
        },
    ]).then(async function(posts) {
        //some code here
    });

问题是这给了我一个 user_id 的空数组。以下是我收到的一个输出。

{ _id: 5ee1f89732fd2c33bccfec55,
    post_data: 'vvhhh',
    likes: 1,
    commentsCount: 0,
    post_img: null,
    isUserLiked: false,
    usersLiked: [ 5edf43b93859680cf815e577 ],
    exp_date: 2020-06-12T18:30:00.000Z,
    has_img: false,
    typology: 'chat',
    geometry:
     { pintype: 'Point',
       _id: 5ee1f89732fd2c33bccfec56,
       coordinates: [Array] },
    category: [],
    created: 1591867543468,
    createdAt: 2020-06-11T09:25:43.478Z,
    updatedAt: 2020-06-15T10:01:01.133Z,
    user_id: [] }

在我的情况下,我不希望它为 null,我希望得到如下所示的输出。

{ _id: 5ee1f89732fd2c33bccfec55,
post_data: 'vvhhh',
likes: 1,
commentsCount: 0,
post_img: null,
isUserLiked: false,
usersLiked: [ 5edf43b93859680cf815e577 ],
exp_date: 2020-06-12T18:30:00.000Z,
has_img: false,
typology: 'chat',
geometry:
 { pintype: 'Point',
   _id: 5ee1f89732fd2c33bccfec56,
   coordinates: [Array] },
category: [],
created: 1591867543468,
createdAt: 2020-06-11T09:25:43.478Z,
updatedAt: 2020-06-15T10:01:01.133Z,
user_id:  { img: 'default-user-profile-image.png',
   _id: 5edd103214ce223088a59236,
   user_name: 'Puka' }
}

我的 userSchema 如下所示

var userSchema = mongoose.Schema({
//some other fields
    user_name: {
        type: String,
        max: 30,
        min: 5
    },

    img: {
        type: String,
        default: 'default-user-profile-image.png'

    },
//some other fields
});
userSchema.plugin(uniqueValidator);
var userSchemaModel = mongoose.model('users', userSchema);

module.exports = {
    userSchemaModel,
}

根据此处的其他答案,我尝试使用 mongoose.Types.ObjectId(userId), 但它提供了完整的空集。

这可能是什么问题,如果有人可以帮助我解决这个问题,那将非常有帮助,因为我已经坚持了好几天了。

更新: 发布架构

var postSchema = mongoose.Schema({
    user_id: {
        type: String,
        required: true,
        ref: 'users'
    },
//other fields
var postSchemaModel = mongoose.model('posts', postSchema);
module.exports = {
    postSchemaModel,
}

【问题讨论】:

  • postSchemaModel 的架构是什么?
  • 是否有任何特殊原因将 post.user_id 存储为 String 而不是 ObjectId?可以改成ObjectId吗?
  • @thammada 我也使用了mongoose.Types.ObjectId,但结果是一样的。空
  • 您还必须更改现有数据,而不仅仅是架构
  • @thammada 非常感谢。在我更改为 ObjectId 并清理集合后,它正在工作。欣赏

标签: node.js mongodb mongoose mongodb-query aggregation-framework


【解决方案1】:

由于user._id(ObjectId) 和post.user_id(String) 的数据类型不同,您不能使用$lookup 连接这些字段。在执行$lookup之前,您必须确保它们是相同的类型

如果允许更改架构,建议使用ObjectId 替换post.user_id

var postSchema = mongoose.Schema({
    user_id: {
        type: mongoose.Types.ObjectId,
        required: true,
        ref: 'users'
    },
    // ...other fields

但请记住将现有数据类型也更改为ObjectId。

如果您真的不允许出于某种原因更改架构和现有数据。您可以将 post.user_id 转换为 ObjectId,以防数据包含 ObjectId 的有效十六进制表示(可从 MongoDB v4.0 获得)

[
// prior pipeline stages
{ "$sort": { "createdAt": -1 } },
{
  "$addFields": {
    "user_id": { "$toObjectId": "$user_id" }
  }
},
{
  "$lookup": {
    "from": userSchemaModel.collection.name,
    "localField": "user_id",
    "foreignField": "_id",
    "as": "user_id"
  }
},
// other stages        

【讨论】:

    【解决方案2】:

    由于mongodb中的_id字段存储为ObjectId类型,但在posts集合中user_id存储为string类型,因此无法找到用户信息并带来空白数组。

    要解决此问题,请在创建用户时将 _id 的纯字符串版本保存在 user 集合中。例如

    { 
      _id: ObjectId("5ee1f89732fd2c33bccfec55"),
      doc_id: "5ee1f89732fd2c33bccfec55",
      //other user info
    }
    

    然后在 $lookup 中使用 doc_id 字段

    {
      "$lookup": {
          "from": userSchemaModel.collection.name,
          "localField": "user_id",
          "foreignField": "doc_id",
          "as": "user_id"
      }
    }
    

    这样user_id 和doc_id 都将是string 类型,并且不需要任何类型转换的麻烦。

    【讨论】:

      猜你喜欢
      • 2020-09-14
      • 2019-04-27
      • 2018-02-03
      • 2021-09-16
      • 1970-01-01
      • 1970-01-01
      • 2018-08-27
      • 2019-04-15
      相关资源
      最近更新 更多