限制从集合中选择数据(搜索的每个ID的最后一个文档)。

huangapple go评论86阅读模式
英文:

Limit the selection of data (the last document for each ID searched for) from the collection

问题

我正在尝试为每个聊天室获取最近用户消息的数组。但是在我的版本中,我只得到了一个包含所有聊天中发送的消息的数组。

func (r *Mongo) findLastMessages(ctx context.Context, chatIds []string) ([]*Message, error) {

	if len(chatIds) == 0 {
		return nil, nil
	}

	query := bson.M{"chat_id": bson.M{"$in": chatIds}}
	cursor, err := r.colMessage.Find(ctx, query, nil)
	if err != nil {
		return nil, err
	}

	var messages []*Message
	if err = cursor.All(ctx, &messages); err != nil {
		return nil, err
	}

	err = cursor.Close(ctx)
	if err != nil {
		return nil, ErrInternal
	}

	return messages, err
}

有没有办法过滤样本,以便我只获取每个聊天的最后一条消息?

并且

也许你应该使用聚合来实现这样的目的?如果是这样,是循环使用Find还是使用聚合更好?

英文:

I'm trying to get an array of recent user messages for each chat room. But in my version I get just an array of messages that have been sent for all the chats.

func (r *Mongo) findLastMessages(ctx context.Context, chatIds []string) ([]*Message, error) {

	if len(chatIds) == 0 {
		return nil, nil
	}

	query := bson.M{"chat_id": bson.M{"$in": chatIds}}
	cursor, err := r.colMessage.Find(ctx, query, nil)
	if err != nil {
		return nil, err
	}

	var messages []*Message
	if err = cursor.All(ctx, &messages); err != nil {
		return nil, err
	}

	err = cursor.Close(ctx)
	if err != nil {
		return nil, ErrInternal
	}

	return messages, err
}

Is there any way I can filter the sample so that I get only one last message for each chat?

And

Perhaps you should use aggregations for such purposes? If so, is it better to cycle Find or use aggregations?

答案1

得分: 1

假设你所说的“最后一个”是指具有最近时间戳的那个,我可以想到两种方法来实现。

如果chat_id和timestamp上都有索引,两种方法都会表现得更好。

1)找到匹配单个chat_id的记录,按照时间戳降序排序,并限制返回结果为1条。这样只需要加载所需的文档,返回的扫描比例为1:1。对于每个chat重复此操作。

2)使用聚合操作一次匹配一个chats数组,按照时间戳排序,然后按chat_id分组,只选择每个组中的第一条消息。这样需要加载每个chat的许多消息。然而,这种方法将在单个操作和单个网络往返中返回所有文档。

哪种方法更好取决于以下因素:

  • 网络往返的开销有多大
  • 由于扫描所有额外文档的资源开销,会有多少延迟
  • 查询的频率有多高
  • 同时运行查询的实例数量有多少
英文:

Assuming that by "last" you mean the one with the most recent timestamp, I can think of 2 ways to do it.

Both will perform better if there is an index on chat_id:1, timestamp:1

  1. Find matching a single chat_it, sort by timestamp descending, with a limit of 1. This would require loading only the desired document, for a 1:1 scanned returned ratio. Repeat for each chat

  2. Aggregation to match an array ofchats at once, sort by timestamp, and then group by chat_id selecting only the first message from each. This would require loading many messages from each chat. However, this method would return all of the documents in a single operation with a single network round trip.

Which method is better for you would depend on:

  • how expensive is the network round trip
  • how much delay will there be due to the resource overhead of scanning all of the extra documents
  • how often the query will run
  • how many instances of the query will be run simultaneously

huangapple
  • 本文由 发表于 2022年12月28日 20:57:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/74940548.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定