В качестве базы данных я использую express/nodejs (без mongoose) и mongodb. У меня есть коллекция страниц, которая выглядит примерно так
{
_id: ..
Urls: [
{
IncomingUrl: "/test/test1",
Status: "active",
},
{
IncomingUrl: "/test/test2",
Status: "active",
}
],
DraftUrls: [
// same structure as Urls
]
//other fields which arent related to the ques
}
Теперь, создавая страницу, я просматриваю эту коллекцию, чтобы определить, существует ли какой-либо URL-адрес в массиве URL-адресов, который я предоставляю в теле запроса, в каком-либо существующем документе страницы.
И если есть повторяющийся URL-адрес, предоставьте в ответ список повторяющихся URL-адресов.
Теперь проблема, с которой я столкнулся, заключается в том, что если бы мне просто нужно было получить счетчик, я мог бы использовать фильтр поиска, например
const filter = { $or: [
{ "Urls.IncomingUrl": { $in: urls } },
{ "DraftUrls.IncomingUrl": { $in: urls } }
] }
А затем использовал запрос типа
db.collection(PageCollection).find(filter).countDocuments();
И это дало бы количество повторяющихся URL-адресов.
Но в моем случае мне нужно получить повторяющиеся URL-адреса, а не счетчик, поэтому, если я использую что-то вроде этого
const duplicateUrlPages = db.collection(PageCollection).find(filter).toArray();
А затем запустите вложенный цикл for для URL-адресов и дубликатовUrlPages, тогда это будет слишком дорого.
Может ли кто-нибудь подсказать, как я могу эффективно получить только список URL-адресов среди входных URL-адресов, которые уже существуют в любом документе страницы под его Urls.IncomingUrl или DraftUrls.IncomingUrl
Пример:
Предположим, в моей БД есть два таких документа.
Document1: {
// ....
Urls: [
{ IncomingUrl: "test1", status: "active" },
// ...
],
DraftUrls: [
{ IncomingUrl: "test2", status: "inactive" },
// ...
]
}
Document2: {
// ....
Urls: [
{ IncomingUrl: "test4", status: "active" },
// ...
],
DraftUrls: [
{ IncomingUrl: "test10", status: "inactive" },
// ...
]
}
И я предоставляю тело функции контроллера запросов POST как
{
// ...
urls: ["test1", "test2", "test3", "test4"]
}
Затем мне нужен массив ответов, например:
["test1", "test2", "test4"]
Поскольку test1, test2 и test4 уже существуют.
@cmgchess я упомянул, что при создании страницы я предоставляю массив URL-адресов. Перед созданием страницы я проверяю, присутствует ли какой-либо из этих URL-адресов в БД в разделе Urls.IncomingUrl или DraftUrls.IncomingUrl. Если да, мне нужны все эти URL-адреса в виде списка.
@cmgchess предоставил пример в конце вопроса
Возможно, вы захотите провести рефакторинг и объединить массивы URL-адресов в отдельные документы, такие как коллекция PageUrl на этой игровой площадке, поскольку вы много работаете на уровне URL-адресов. Вы также можете проиндексировать поле IncomingUrl, чтобы повысить производительность.
@ray, я понимаю, что ты пытаешься сказать, но я не могу это реорганизовать, так как мне нужно разделить действующие и черновые URL-адреса на URL-адреса и DraftUrls (это требование проекта). И да, я реализовал индексацию IncomingUrl в Urls и DraftUrls. В любом случае спасибо за предложения.
@JayendraAwasthi Вы можете увидеть флаг isDraft в новой структуре документа. Извините за опечатку на предыдущей площадке. Вот правильный.
@ray, да, я понял, что могу использовать флаг для хранения как живых, так и черновых URL-адресов в PageUrls. Но, как я уже сказал, я не могу изменить существующую структуру коллекции, поскольку от нее зависят многие другие функции.





Вы можете использовать агрегацию.
$match: копирует ваши $or условия filter объекта.$project: измените форму документов, $filter изменив массивы настроек Urls и DraftUrls так, чтобы они содержали только совпадения с вашими $match условиями. По сути, это позволит избавиться от объектов, подобных тем, которые содержат test10 в ваших образцах документов.$project: выведите Urls и DraftUrls как один массив с именем urls.$unwind: новый массив urls на отдельные объекты.$group: эти новые объекты и добавьте значения в один массив, используя $addToSet, чтобы избежать дублирования.$project: дополнительный этап, позволяющий избавиться от избыточного поля _id.const urls = ["test1", "test2", "test3", "test4"];
const filter = { $or: [
{ "Urls.IncomingUrl": { $in: urls } },
{ "DraftUrls.IncomingUrl": { $in: urls } }
] }
db.collection(PageCollection).aggregate([
{
$match: filter
},
{
$project: {
"Urls": {
$map: {
input: {
$filter: {
input: "$Urls",
as: "u",
cond: {
$in: [
"$$u.IncomingUrl",
urls
]
}
}
},
as: "rls",
in: "$$rls.IncomingUrl"
}
},
"DraftUrls": {
$map: {
input: {
$filter: {
input: "$DraftUrls",
as: "du",
cond: {
$in: [
"$$du.IncomingUrl",
urls
]
}
}
},
as: "drls",
in: "$$drls.IncomingUrl"
}
}
}
},
{
$project: {
urls: {
$concatArrays: [
"$DraftUrls",
"$Urls"
]
},
_id: 0
}
},
{
$unwind: "$urls"
},
{
$group: {
_id: null,
urls: {
$addToSet: "$urls"
}
}
},
{
$project: {
_id: 0
}
}
])
Рабочий пример смотрите ЗДЕСЬ.
Спасибо, я уже публиковал свое решение, похожее на эту совокупность, но вчера некоторые «великие умы» подумали об удалении моего ответа из моего собственного сообщения только потому, что я упомянул: «Я хотел бы знать, смогу ли я оптимизировать этот ответ в дальнейшем» :). В любом случае спасибо за помощь, я отмечу это как решение, так как оно почти такое же, как мой ответ.
Возможно, вам повезет, если вы опубликуете свой ответ как другой вопрос. Таким образом, кто-то сможет ответить на этот вопрос более оптимизированным ответом. Агрегации всегда можно оптимизировать, но лучше всего указать свои параметры, т. е. быстрее, использовать меньше этапов или где внедрять индексы и т. д.
конечно… опубликую, когда будет время. Спасибо
что вы подразумеваете под повторяющимися URL-адресами. можешь ли ты привести пример