我正在运行iOS应用,其中显示当前在线的用户列表 我有一个API端点,我随机返回10(或N)个用户,这样你就可以继续滚动并始终看到新用户。因此,我想确保我不会返回之前已经返回的用户 我无法使用游标或普通分页,因为用户必须随机返回。
我尝试了两件事,但我确信有更好的方法:
我无法弄清楚如何以更好/更清洁的方式做到这一点
编辑: 我找到了一种方法来使用MySQL,使用RAND(种子) 但我无法弄清楚是否有办法与Mongo做同样的事情 PHP MySQL pagination with random ordering
谢谢:))
答案 0 :(得分:1)
我认为,每次只能保证用户看到唯一用户的唯一方法是存储已经看过的用户列表。即使在您链接到的RAND
示例中,也有可能与之前的用户列表相交,因为RAND
无法排除先前返回的用户。
如果您确实想要随机抽样,请考虑Random record from MongoDB,建议使用Aggregation和$sample
运算符。实现看起来像这样:
const {
MongoClient
} = require("mongodb");
const
DB_NAME = "weather",
COLLECTION_NAME = "readings",
MONGO_DOMAIN = "localhost",
MONGO_PORT = "32768",
MONGO_URL = `mongodb://${MONGO_DOMAIN}:${MONGO_PORT}`;
(async function () {
const client = await MongoClient.connect(MONGO_URL),
db = await client.db(DB_NAME),
collection = await db.collection(COLLECTION_NAME);
const randomDocs = await collection
.aggregate([{
$sample: {
size: 5
}
}])
.map(doc => {
return {
id: doc._id,
temperature: doc.main.temp
}
});
randomDocs.forEach(doc => console.log(`ID: ${doc.id} | Temperature: ${doc.temperature}`));
client.close();
}());
如果您维护以前查看过的用户列表,可以使用$nin
过滤器编写实现,并存储以前查看过的用户_id
。
以下是使用天气数据库的示例,我一次返回条目5,直到所有条目都被打印出来:
const {
MongoClient
} = require("mongodb");
const
DB_NAME = "weather",
COLLECTION_NAME = "readings",
MONGO_DOMAIN = "localhost",
MONGO_PORT = "32768",
MONGO_URL = `mongodb://${MONGO_DOMAIN}:${MONGO_PORT}`;
(async function () {
const client = await MongoClient.connect(MONGO_URL),
db = await client.db(DB_NAME),
collection = await db.collection(COLLECTION_NAME);
let previousEntries = [], // Track ids of things we have seen
empty = false;
while (!empty) {
const findFilter = {};
if (previousEntries.length) {
findFilter._id = {
$nin: previousEntries
}
}
// Get items 5 at a time
const docs = await collection
.find(findFilter, {
limit: 5,
projection: {
main: 1
}
})
.map(doc => {
return {
id: doc._id,
temperature: doc.main.temp
}
})
.toArray();
// Keep track of already seen items
previousEntries = previousEntries.concat(docs.map(doc => doc.id));
// Are we still getting items?
console.log(docs.length);
empty = !docs.length;
// Print out the docs
docs.forEach(doc => console.log(`ID: ${doc.id} | Temperature: ${doc.temperature}`));
}
client.close();
}());
答案 1 :(得分:0)
我遇到了同样的问题,可以提出替代解决方案。
TL;DR:在第一次登陆时获取集合的所有对象 ID,使用 NodeJS 随机化,稍后使用。
让我们开始详细解释:)
为了更好的解释,我将做以下假设
注意:我确实考虑了性能,对于 10,000 个大小的集合,此执行需要几秒钟的时间。如果您正在解决一百万条记录问题,那么可能首先使用某种形式的分区逻辑/使用列出的其他解决方案
db.getCollection('my_collection').find({}, {_id:1}).map(function(item){ return item._id; });
或
db.getCollection('my_collection').find({}, {_id:1}).map(function(item){ return item._id.valueOf(); });
结果:
ObjectId("FirstObjectID"),
ObjectId("SecondObjectID"),
ObjectId("ThirdObjectID"),
ObjectId("ForthObjectID"),
结果:
ObjectId("ThirdObjectID"),
ObjectId("SecondObjectID"),
ObjectId("ForthObjectID"),
ObjectId("FirstObjectID"),
检索存储的数组
抓取分页项,(例如前 2 项)
使用 find $in 查找这些项目的对象
.
db.getCollection('my_collection')
.find({"_id" : {"$in" : [ObjectId("ThirdObjectID"), ObjectId("SecondObjectID")]}});
你去吧!用于分页的随机 MongoDB 查询 :)