1

情况

  • 我有一个提供以下功能的消息传递 Android 应用程序
    • 向一个选定的收件人发送消息直接消息
    • 创建所有使用该应用程序的用户都会收到的公告(作者除外)
    • 每个用户都会在他的手机上看到他收到的消息列表
    • 每条消息都是未读、已读或已删除
  • 我使用 Parse.com 作为后端

当前实施

在安卓客户端

  1. 当有新消息时,MessageRequest创建该类的新 messageRequest
  2. 如果消息应该是直接的,则 messageRequest 的类型为 0,否则为类型 1
  3. 如果消息是直接的,则在 messageRequest 对象中存储有接收者
  4. messageRequest 对象存储到 parse.com

在 parse.com 后端

afterSaveMessageRequest 中,检查消息是直接的还是公开的,并基于此

  • Message在直接消息的情况下 -创建并保存该类的一个新消息对象
  • 在公告的情况下 - 对于除作者之外的每个用户,都会创建一个新的消息对象并将其添加到消息列表中,然后保存该列表

在这两种情况下,内容、类型等数据都从 messageRequest 对象复制到新创建的消息对象中。

为每个用户创建单独消息的原因是每个用户都可以将其置于另一个状态(未读、已读、已删除)。

表示未读、已读、已删除状态的状态列为消息对象设置(按未读)。

问题

当我调用MessageRequestParseObject.saveAll中的方法时afterSave,我得到Execution timed out - Request timed out 错误

我认为原因是请求必须在云代码中完成的时间有一些限制。就我而言,我正在为 1 MessageRequest 创建 ca 100 Messages

这对我来说似乎并不多,但也许我错了。

源代码

var generateAnnouncement = function(messageRequest, recipients) {

    var messageList = [];

    for (var i = 0; i < recipients.length; i++) {
        var msg = new Message();
        msg.set("type", 1);
        msg.set("author", messageRequest.get("author"));
        msg.set("content", messageRequest.get("content"));
        msg.set("recipient", recipients[i]);
        msg.set("status", 0)

        messageList.push(msg);
    }

    Parse.Object.saveAll(messageList).then(function(list) {
    }, function(error) {
        console.error(error.message);
    });

}

Parse.Cloud.afterSave("MessageRequest", function(request) {
    var mr = request.object;
    var type = mr.get("type");

    if (type == 0) {
        generateDirectMessage(mr);
    } else {
        var query = new Parse.Query(Parse.User);
        query.notEqualTo("objectId", mr.get("author").id);
        query.find().then(function(allUsersExceptAuthor) {
            generateAnnouncement(mr, allUsersExceptAuthor);
        }, function(error) {
            console.error(error.message);
        });
    }
});

你会建议如何解决这个问题?

额外的想法

  • 如何解决这个问题我唯一的另一个想法是只有一个 Message 对象,以及两个名为例如viewedBy 和deletedFor 的列,其中将包含已经查看该消息或已为他们删除该消息的用户列表。
  • 在这种情况下,我不太确定查询的性能

  • 另外,我知道,你们中的许多人认为他为什么不使用表来拆分 MessageRequest(在这种情况下实际上可以称为 Message)和 User 之间的 M:N 关系?

  • 我的回答是我有这个解决方案,但是在 Android 代码中更难使用它,更多的指针,更多的包含在查询等中。
  • 此外,无论如何,我必须在 on parse.com 后端为每个用户创建相同数量的表示状态的对象,所以我认为执行超时的问题最终会是相同的

更新 - 代表用户“收件箱”的模型

收件箱模型

在“收件箱”中,用户可以看到直接消息和公告。它们按时间顺序排列。

更新 #2 - 使用数组来识别谁查看了谁标记为已删除

  • 我只有一个Message对象,通过类型确定它是直接的还是公共的
  • 添加了两个数组列
    • viewedBy- 包含已查看消息的用户
    • deletedFor- 包含将邮件标记为已删除的用户

然后我对当前登录用户未删除的所有消息的查询如下所示

//direct messages for me
ParseQuery<Message> queryDirect = ParseQuery.getQuery(Message.class);
queryDirect.whereEqualTo("type", 0);
queryDirect.whereEqualTo("recipient", ParseUser.getCurrentUser());

//public announcements
ParseQuery<Message> queryAnnouncements = ParseQuery.getQuery(Message.class);
queryAnnouncements.whereEqualTo("type", 1);

//I want both direct and public
List<ParseQuery<Message>> queries = new ArrayList<ParseQuery<Message>>();
queries.add(queryDirect);
queries.add(queryAnnouncements);

ParseQuery<Message> queryMessages = ParseQuery.or(queries);
//... but only those which I haven't deleted for myself
queryMessages.whereNotEqualTo("deletedFor", ParseUser.getCurrentUser());
//puting them in correct order
queryMessages.addDescendingOrder("createdAt");
//and attaching the author ParseUser object (to get e.g. his name or URL to photo)
queryMessages.include("author");
queryMessages.findInBackground(new FindCallback<Message>() {/*DO SOMETHING HERE*/});
4

1 回答 1

1

我建议更改您的架构以更好地支持公共消息。

您应该拥有一份公开消息的副本,因为消息本身不会发生变化。

如果不是“未读”,您应该只存储每个用户的状态。这将是另一张桌子。

当 MessageRequest 以类型 1 出现时,创建一个新的PublicMessage,不要创建任何状态行,因为每个人都将使用默认状态“未读”。这使您的afterSave处理程序可以干净地工作,因为它总是只创建一个新对象,要么 aMessage要么 a PublicMessage

当每个用户阅读或删除消息时,PublicMessageStatus为该用户创建具有正确状态的新行。

向用户显示公共消息时,您将执行两个查询:

  1. 查询PublicMessage,可能有一些日期范围
  2. 使用第一个查询的克隆来查询匹配当前用户和约束PublicMessageStatus的过滤器usermatchesQuery('publicMessage', publicMessageQuery)

在客户端,您需要将两者结合起来以隐藏/删除状态为“已删除”的那些,并相应地标记状态为“已读”的那些。

根据反馈更新

您可以选择使用单个Message类来处理公共/私人消息,并使用一个MessageStatus类来处理状态。

公共与私人将基于是否Message.recipient为空。

获取当前用户的所有消息:

// JavaScript sample since you haven't specified a language
// assumes Underscore library available

var Message = Parse.Object.extend('Message');
var MessageStatus = Parse.Object.extend('MessageStatus');

var publicMessageQuery = new Parse.Query(Message);
publicMessageQuery.doesNotExist('recipient');
publicMessageQuery.notEqualTo('author', currentUser);

var privateMessageQuery = new Parse.Query(Message);
privateMessageQuery.equalTo('recipient', currentUser);

var messagesQuery = new Parse.Query.or(publicMessageQuery, privateMessageQuery);
messagesQuery.descending('createdAt');
// set any other filters to apply to both queries

var messages = [];
messageQuery.find().then(function(results) {
    messages = _(results).map(function (message) {
        return { message: message, status: 'unread', messageId: message.objectId };
    });
    var statusQuery = new Parse.Query(MessageStatus);
    statusQuery.containedIn('message', results);
    statusQuery.equalTo('user', currentUser);
    // process status in order so last applies
    statusQuery.ascending('createdAt');
    return
}).then(function(results) {
    _(results).each(function (messageStatus) {
        var messageId = messageStatus.get('message').objectId;
        _(messages).findWhere({ messageId: messageId }).status = messageStatus.get('status');
    });
});

// optionally filter messages that are deleted
messages = _(messages).filter(function(message) { return message.status !== 'deleted'; });

// feed messages array to UI...
于 2014-07-02T16:24:23.223 回答