Как реализовать теги записей в Mongo?

Я играю с Mongo, чтобы сделать проект, подобный домашнему животному, и хочу реализовать теги post. У каждого тега есть имя и слаг (строка, которая будет использоваться в качестве идентификатора в URL), а у записи есть несколько тегов. Я хотел бы иметь возможность создавать запросы типа "найти сообщения, которые имеют тег A, не имеют тег B", и мне интересно, как это можно сделать.

Одним из способов является сохранение массива идентификаторов тегов для каждого сообщения - это облегчит указанный запрос, но потребует дополнительного для каждого сообщения, чтобы получить имя тега и фрагмент. Другой способ - сохранить массив [tag name, tag slug] с каждым сообщением, но я не уверен, что смогу использовать эту информацию в find,

Есть какой-то другой метод, который будет работать лучше для монго? Я новичок в NoSQL, поэтому я буду признателен за любые советы о том, как это можно сделать. Кроме того, я использую привязку PHP, но это не должно иметь значения, вероятно.

1 ответ

Решение

Если теги, которые вы используете, и их соответствующие слагы вряд ли изменятся, я думаю, что ваш второй подход лучше. Однако я бы предложил небольшое изменение - вместо того, чтобы хранить массив [name, slug], сделайте поля явными, создав поддокумент тега, как в этом примере post документ:

{
    "_id" : ObjectId("4ee33229d8854784468cda7e"),
    "title" : "My Post",
    "content" : "This is a post with some tags",
    "tags" : [
        {
            "name" : "meta",
            "slug" : "34589734"
        },
        {
            "name" : "post",
            "slug" : "34asd97x"
        },
    ]
}

Затем вы можете запросить сообщения с определенным тегом с помощью точечной нотации, например:

db.test.find({ "tags.name" : "meta"})

Так как tags является массивом, монго достаточно умен, чтобы сопоставить запрос с любым элементом массива, а не с массивом в целом, а точечная нотация позволяет сопоставить конкретное поле.

Для запроса сообщений, не содержащих определенный тег, используйте $ne:

db.test.find({ "tags.name" : { $ne : "fish" }})

И для запроса сообщений, содержащих один тег, но не другой, используйте $and:

db.test.find({ $and : [{ "tags.name" : { $ne : "fish"}}, {"tags.name" : "meta"}]})

Надеюсь это поможет!

Другие вопросы по тегам