猫鼬:find() 忽略重复值 [英] Mongoose: find() ignore duplicate values
问题描述
我有一个聊天"猫鼬 Schema
,它具有以下属性:
const schema = mongoose.Schema({...接受者: {类型:猫鼬.Types.ObjectId,要求:真实,参考:'用户',},发件人:{类型:猫鼬.Types.ObjectId,要求:真实,参考:'用户',},内容: {类型:字符串,},...}, {时间戳:真实,});
通常,我想获取用户拥有的每个报道的最后一条消息.这意味着我需要提供一个用户 ID(可以存储在 sender
或 recipient
字段中)并取回最后一条消息(由 createdAt<表示)/code>) 用户与其他每个用户都有过.
示例:假设我有以下 document
s:
[{收件人:一个",发件人:两个",createdAt: ISODate("2014-01-01T08:00:00Z"),},{收件人:一个",发件人:三",createdAt: ISODate("2014-02-15T08:00:00Z")},{收件人:两个",发件人:一个",createdAt: ISODate("2014-02-16T12:05:10Z")}]
插入One"作为输入 - Model.find(...)
的期望结果是:
[{收件人:一个",发件人:三",createdAt: ISODate("2014-02-15T08:00:00Z")},{收件人:两个",发件人:一个",createdAt: ISODate("2014-02-16T12:05:10Z")}]
使用示例数据:
<预><代码>[{收件人:一个",发件人:两个",createdAt: ISODate("2014-01-01T08:00:00Z"),内容:一号先生你好!-二号"},{收件人:一个",发件人:三",createdAt: ISODate("2014-02-15T08:00:00Z"),内容:你好一!-三"},{收件人:两个",发件人:一个",createdAt: ISODate("2014-02-16T12:05:10Z"),内容:怎么了,二?-一"}]查看以下聚合:https://mongoplayground.net/p/DTSDWX3aLWe
它...
- 使用 $match 按收件人或发件人过滤所有邮件.返回匹配当前用户的那些 (
One
) - 使用包含
recipient
的 $addFields 添加一个conversationWith
字段,如果它是给用户 One 的消息或者sender
如果是用户发送的消息 - 使用 $sort 按日期对邮件进行排序
- 使用 $group 通过新的
conversationWith
字段对所有消息进行分组,并以firstMessage
形式返回最近的消息
完整的聚合管道:
db.collection.aggregate([{$匹配:{$和:[{$或:[{收件人:一个"},{发件人:一个"}],},]}},{$addFields:{对话:{$cond: {如果: {$eq: ["$sender",一"]},然后:$recipient",其他:$sender"}}}},{$排序:{创建于:-1}},{$组:{_id: "$conversationWith",第一条消息:{$first: "$$ROOT"}}}])
使用 mongoplayground,您可以一一删除聚合步骤,以查看每个步骤的作用.
试试:
- 仅$match步骤
- $match + $addFields
- $match + $addFields + $sort
- [..]
为了最好的理解.
I have a "chat" mongoose Schema
which has the following properties:
const schema = mongoose.Schema({
...
recipient: {
type: mongoose.Types.ObjectId,
required: true,
ref: 'User',
},
sender: {
type: mongoose.Types.ObjectId,
required: true,
ref: 'User',
},
content: {
type: String,
},
...
}, {
timestamps: true,
});
Generally, I want to fetch the last message of each coversation that a user has. Meaning that I need to provide a user id (that can be either stored in the sender
or recipient
field) and get back the last message (indicated by createdAt
) the user had with each of the other users.
Example:
Let's say I have the following document
s:
[
{
recipient: "One",
sender: "Two",
createdAt: ISODate("2014-01-01T08:00:00Z"),
},
{
recipient: "One",
sender: "Three",
createdAt: ISODate("2014-02-15T08:00:00Z")
},
{
recipient: "Two",
sender: "One",
createdAt: ISODate("2014-02-16T12:05:10Z")
}
]
Instering "One" as input - the desired result from Model.find(...)
is:
[
{
recipient: "One",
sender: "Three",
createdAt: ISODate("2014-02-15T08:00:00Z")
},
{
recipient: "Two",
sender: "One",
createdAt: ISODate("2014-02-16T12:05:10Z")
}
]
Using the example data:
[
{
recipient: "One",
sender: "Two",
createdAt: ISODate("2014-01-01T08:00:00Z"),
content: "Hi Mr. One! - Two"
},
{
recipient: "One",
sender: "Three",
createdAt: ISODate("2014-02-15T08:00:00Z"),
content: "Hello One! - Three"
},
{
recipient: "Two",
sender: "One",
createdAt: ISODate("2014-02-16T12:05:10Z"),
content: "Whats up, Two? - One"
}
]
Have a look at the following aggregation: https://mongoplayground.net/p/DTSDWX3aLWe
It...
- Uses $match to filter all messages by recipient or sender. Returns the ones matching the current user (
One
) - Adds a
conversationWith
field using $addFields that contains therecipient
if it is a message to user One or thesender
if it is a message sent by user One - Sorts the messages by date using $sort
- Groups all the messages using $group by the new
conversationWith
field and returns the most recent message asfirstMessage
The full aggregation pipeline:
db.collection.aggregate([
{
$match: {
$and: [
{
$or: [
{
recipient: "One"
},
{
sender: "One"
}
],
},
]
}
},
{
$addFields: {
conversationWith: {
$cond: {
if: {
$eq: [
"$sender",
"One"
]
},
then: "$recipient",
else: "$sender"
}
}
}
},
{
$sort: {
createdAt: -1
}
},
{
$group: {
_id: "$conversationWith",
firstMessage: {
$first: "$$ROOT"
}
}
}
])
Using mongoplayground you can remove the aggregation steps one-by-one to see what each step does.
Try:
- Only the $match step
- $match + $addFields
- $match + $addFields + $sort
- [..]
for best understanding.
这篇关于猫鼬:find() 忽略重复值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!