如何查询以一个字段为用户名获取引用到另一个集合的所有文档

时间:2020-02-06 12:35:33

标签: mongodb mongodb-query aggregation-framework

在我的Node API和MongoDB中,我试图建立一个端点来获取与一个配置文件的一个用户名关联的所有帖子。在我的Profile模式中,我引用了Post模式,在Post模式中,我引用了Profile模式中的Username。 我的问题是我不知道如何获取该用户名的所有帖子。我做了类似的工作,但是为Experience模式嵌入了,但是我不确定如何对引用的集合执行此操作。

发布模型:

const { Connect } = require("../db");

const reactionSchema = {
    likedBy: {
        type: String,
        unique: true,
        sparse: true
    }
};

const postSchema = {
    text: {
        type: String,
        required: true,
        unique: true,
        sparse: false
    },    
    username: {
        type: Connect.Schema.Types.String,
        ref: "Profile"
    },    
    image: {
        type: String,
        default: "https://via.placeholder.com/150",
        required: false
    },
    createdAt: {
        type: Date,
        default: Date.now,
        required: false
    },    
    updatedAt: {
        type: Date,
        default: Date.now,
        required: false
    },    
    reactions: [reactionSchema],    
    comments: {
        type: Connect.Schema.Types.ObjectId,
        ref: "Comment",
        required: false
    }
};

const collectionName = "post";
const postSchemaModel = Connect.Schema(postSchema);
const Post = Connect.model(collectionName, postSchemaModel);

module.exports = Post;

个人资料模型:

// Here defining profile model
// Embedded we have the Experience as []
const { Connect } = require("../db");
const { isEmail } = require("validator");

const postSchema = {
    type: Connect.Schema.Types.ObjectId,
    ref: "Post"
};

const experienceSchema = {
    role: {
        type: String,
        required: true
    },
    company: {
        type: String,
        required: true
    },
    startDate: {
        type: Date,
        required: true
    },
    endDate: {
        type: Date,
        required: false
    },
    description: {
        type: String,
        required: false
    },    
    area: {
        type: String,
        required: true
    },
    createdAt: {
        type: Date,
        default: Date.now,
        required: false
    },    
    updatedAt: {
        type: Date,
        default: Date.now,
        required: false
    },    
    username: {
        type: String,
        required: false
    },
    image: {
        type: String,
        required: false,
        default: "https://via.placeholder.com/150"
    }
};

const profileSchema = {
    firstname: {
        type: String,
        required: true
    },   
    surname: {
        type: String,
        required: true
    },    
    email: {
        type: String,
        trim: true,
        lowercase: true,
        unique: true,
        required: [true, "Email is required"],
        validate: {
            validator: string => isEmail(string),
            message: "Provided email is invalid"
        }
    },    
    bio: {
        type: String,
        required: true
    },    
    title: {
        type: String,
        required: true
    },    
    area: {
        type: String,
        required: true
    },    
    imageUrl: {
        type: String,
        required: false,
        default: "https://via.placeholder.com/150"
    },    
    username: {
        type: String,
        required: true,
        unique: true
    },    
    experience: [experienceSchema],
    posts: [postSchema],    
    createdAt: {
        type: Date,
        default: Date.now,
        required: false
    },    
    updatedAt: {
        type: Date,
        default: Date.now,
        required: false
    }
};

const collectionName = "profile";
const profileSchemaModel = Connect.Schema(profileSchema);
const Profile = Connect.model(collectionName, profileSchemaModel);

module.exports = Profile;

我能够做到这一点来获得嵌入式体验,但不确定所引用的集合是否正确:

const profileWithExperiences = await Student.aggregate([
  { $match: { username: res.username.username } },
  {
    $unwind: "$experience"
  },
  {
    $match: {
      "experience._id": new ObjectID(req.params.experienceId)
    }
  },
  {
    $project: {
      username: 1,
      experience: 1,
      _id: 0
    }
  }
]);

我想看一个引用集合的示例,因为它使我感到困惑

[编辑] 个人资料和帖子的JSON

{
    "_id": ObjectId("5e2c98fc3d785252ce5b5693"),
    "imageUrl": "https://i.pravatar.cc/300",
    "firstname": "Jakos",
    "surname": "Lemi",
    "email": "lemi@email.com",
    "bio": "My bio bio",
    "title": "Senior IT developer",
    "area": "Copenhagen",
    "username": "Jakos",
    "experience": [
        {
            "image": "https://via.placeholder.com/150",
            "_id": ObjectId("5e3975f95fbeec9095ff3d2f"),
            "role": "Developer",
            "company": "Google",
            "startDate": ISODate("2018-11-09T23:00:00.000Z"),
            "endDate": ISODate("2019-01-05T23:00:00.000Z"),
            "area": "Copenhagen",
            "createdAt": ISODate("2020-02-04T13:47:37.167Z"),
            "updatedAt": ISODate("2020-02-04T13:47:37.167Z")
        },
        {
            "image": "https://via.placeholder.com/150",
            "_id": ObjectId("5e3978bf5e399698e20c56d4"),
            "role": "Developer",
            "company": "IBM",
            "startDate": ISODate("2018-11-09T23:00:00.000Z"),
            "endDate": ISODate("2019-01-05T23:00:00.000Z"),
            "area": "Copenhagen",
            "createdAt": ISODate("2020-02-04T13:59:27.412Z"),
            "updatedAt": ISODate("2020-02-04T13:59:27.412Z")
        }
    ],
    "createdAt": ISODate("2020-01-25T19:37:32.727Z"),
    "updatedAt": ISODate("2020-02-04T23:14:37.122Z"),
    "__v": NumberInt("0")
}

发布

{
    "_id": ObjectId("5e3beb639e072afedd19dcef"),
    "username": ObjectId("5e2c98fc3d785252ce5b5693"),
    "image": "https://via.placeholder.com/150",
    "text": "My awesome post",
    "createdAt": ISODate("2020-02-06T10:33:07.22Z"),
    "updatedAt": ISODate("2020-02-06T10:33:07.22Z"),
    "reactions": [ ],
    "__v": NumberInt("0")
}

预期输出:

{
    "username": "Jakos",
    "postsCount": [1],
    "posts": [
        {
        "_id": ObjectId("5e3beb639e072afedd19dcef"),
        "image": "https://via.placeholder.com/150",
        "text": "My awesome post",
        "createdAt": ISODate("2020-02-06T10:33:07.22Z"),
        "updatedAt": ISODate("2020-02-06T10:33:07.22Z"),
        "reactions": [ ],
        "__v": NumberInt("0")
    }
    ]

}

我想查看与该用户名相关的所有帖子

2 个答案:

答案 0 :(得分:1)

您可以使用$lookup聚合来加入集合。

db.profiles.aggregate([
  {
    $match: {
      username: "Jakos"
    }
  },
  {
    $lookup: {
      from: "posts",   //the name of the posts collection, change this if it is different
      localField: "_id",
      foreignField: "username",
      as: "posts"
    }
  },
  {
    $project: {
      username: 1,
      posts: 1,
      postsCount: {
        $size: "$posts"
      },
      _id: 0
    }
  }
])

Playground

对于mongoose,在您的应用中应该是这样的:

const profileWithExperiences = await Student.aggregate([
  { $match: { username: res.username.username } },
  {
    $unwind: "$experience"
  },
  {
    $lookup: {
      from: "posts", //the name of the posts collection, change this if it is different
      localField: "_id",
      foreignField: "username",
      as: "posts"
    }
  },
  {
    $project: {
      username: 1,
      posts: 1,
      postsCount: {
        $size: "$posts"
      },
      _id: 0
    }
  }
]);

答案 1 :(得分:0)

尝试这样,我正在使用node和mongodb从两个表中获取数据。

var param = {};
    param['user_id']=id;
    var search={ user_id:param.user_id,status: [ 'Pending', 'Accepted' ] };
    var output={};
    output = await JobRequest.find(search); 
    if(output !=0)
    {
            var JSon=await JobRequest.aggregate([
                {$match: { user_id: {$gte:id}}  }, 
                     {
                     "$project": {
                      "employee_id": {
                        "$toObjectId": "$employee_id"
                      }, 
                      "service_id": {
                        "$toObjectId": "$service_id"
                      }, 
                      "createdDate": {
                        "$toString": "$createdDate"
                      }, 
                      "chat_status": {
                        "$toString": "$chat_status"
                      },    
                      "status": {
                        "$toString": "$status"
                      },                      
                      "delivery_address": {
                        "$toString": "$delivery_address"
                      },                 
                      "delivery_lat": {
                        "$toString": "$delivery_lat"
                      },         
                      "delivery_lang": {
                        "$toString": "$delivery_lang"
                      },
                    }
                     },

                     {
                      $lookup:
                         {
                            from: "employees",
                            localField: "employee_id",
                            foreignField: "_id",
                            as: "employee_details"
                        }
                   },
                   {
                      $lookup:
                         {
                            from: "services",
                            localField: "service_id",
                            foreignField: "_id",
                            as: "service_details"
                        }
                   }
               ]);