Реализация фида с ретвитами в MongoDB - PullRequest
0 голосов
/ 02 февраля 2020

Я хочу реализовать функцию ретвита в своем приложении. Я использую Mongoose и у меня есть модели User и Message, и я храню ретвиты как массив объектов типа {userId, createdAt}, где createdAt - время, когда произошел ретвит. Модель сообщения имеет собственное поле createdAt.

Мне нужно создать ленту исходных и ретвитированных сообщений, объединенных вместе на основе полей createdAt. Я застрял с слиянием, делать ли это в одном запросе или в отдельном и сделать слияние в JavaScript. Могу ли я сделать все это в понедельник goose с помощью одного запроса? Если нет, то как найти точки вставки слияния и индекс последнего сообщения?

Пока у меня есть только выборка оригинальных сообщений.

Моя Message модель:

const messageSchema = new mongoose.Schema(
  {
    fileId: {
      type: mongoose.Schema.Types.ObjectId,
      ref: 'File',
      required: true,
    },
    userId: {
      type: mongoose.Schema.Types.ObjectId,
      ref: 'User',
      required: true,
    },
    likesIds: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }],
    reposts: [
      {
        reposterId: {
          type: mongoose.Schema.Types.ObjectId,
          ref: 'User',
        },
        createdAt: { type: Date, default: Date.now },
      },
    ],
  },
  {
    timestamps: true,
  },
);

Редактировать: Теперь у меня есть это, но нумерация страниц нарушена. Я пытаюсь использовать поле newCreatedAt для курсора, который, кажется, не работает. Он возвращает пустой массив при втором вызове, когда newCreatedAt передается из внешнего интерфейса.

  messages: async (
      parent,
      { cursor, limit = 100, username },
      { models },
    ) => {
      const user = username
        ? await models.User.findOne({
            username,
          })
        : null;

      const options = {
        ...(cursor && {
          newCreatedAt: {
            $lt: new Date(fromCursorHash(cursor)), 
          },
        }),
        ...(username && {
          userId: mongoose.Types.ObjectId(user.id),
        }),
      };

      console.log(options);

      const aMessages = await models.Message.aggregate([
        {
          $addFields: {
            newReposts: {
              $concatArrays: [
                [{ createdAt: '$createdAt', original: true }],
                '$reposts',
              ],
            },
          },
        },
        {
          $unwind: '$newReposts',
        },
        {
          $addFields: {
            newCreatedAt: '$newReposts.createdAt',
            original: '$newReposts.original',
          },
        },
        { $match: options },
        {
          $sort: {
            newCreatedAt: -1,
          },
        },
        {
          $limit: limit + 1,
        },
      ]);

      const messages = aMessages.map(m => {
        m.id = m._id.toString();
        return m;
      });
      //console.log(messages);

      const hasNextPage = messages.length > limit;
      const edges = hasNextPage ? messages.slice(0, -1) : messages; 

      return {
        edges,
        pageInfo: {
          hasNextPage,
          endCursor: toCursorHash(
            edges[edges.length - 1].newCreatedAt.toString(),
          ),
        },
      };
    },

Вот запросы. Рабочий:

Mongoose: messages.aggregate([{
    '$match': {
        createdAt: {
            '$lt': 2020 - 02 - 02 T19: 48: 54.000 Z
        }
    }
}, {
    '$sort': {
        createdAt: -1
    }
}, {
    '$limit': 3
}], {})

И нерабочий:

Mongoose: messages.aggregate([{
    '$match': {
        newCreatedAt: {
            '$lt': 2020 - 02 - 02 T19: 51: 39.000 Z
        }
    }
}, {
    '$addFields': {
        newReposts: {
            '$concatArrays': [
                [{
                    createdAt: '$createdAt',
                    original: true
                }], '$reposts'
            ]
        }
    }
}, {
    '$unwind': '$newReposts'
}, {
    '$addFields': {
        newCreatedAt: '$newReposts.createdAt',
        original: '$newReposts.original'
    }
}, {
    '$sort': {
        newCreatedAt: -1
    }
}, {
    '$limit': 3
}], {})

1 Ответ

1 голос
/ 02 февраля 2020

Это можно сделать одним запросом, хотя это немного хак-я sh:

db.collection.aggregate([
    {
        $addFields: {
            reposts: {
                $concatArrays: [[{createdAt: "$createdAt", original: true}],"$reports"]
            }
        }
    },
    {
        $unwind: "$reposts"
    },
    {
        $addFields: {
            createdAt: "$reposts.createdAt",
            original: "$reposts.original"
        }
    },
    {
        $sort: {
            createdAt: -1
        }
    }
]);

Вы можете добавить любые другие логики c, которые вы хотите, к запросу, используя original поля, документы с original: true являются исходными сообщениями, а остальные - ретвитами.

...