# Design документы для CouchDB с поддержкой мультиязычных массивов и наследования # Версия 6.0 - унифицированная структура данных module.exports = # Design документ для универсального поиска по мультиязычному контенту universal_multilingual_search: version: "6.0" views: # Универсальный поиск по всем типам контента с поддержкой массивов content_search: map: ((doc) -> # Пропускаем системные документы if doc._id.startsWith('_design/') or doc.type in ['domain_settings', 'user', 'order', 'setting', 'audit_log'] return domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default'] languages = doc.language or ['ru'] # Базовые поля для поиска searchFields = {} switch doc.type when 'blog_post', 'event', 'product', 'slide' if doc.status is 'published' searchFields = titles: doc.title or [] contents: doc.content or [] excerpts: doc.excerpt or [] authors: doc.author or [] tags: doc.tags or [] type: doc.type languages: languages when 'category' searchFields = names: doc.name or [] descriptions: doc.description or [] type: 'category' languages: languages # Индексируем для каждого домена и языка if searchFields.titles for domain in domains for language, index in languages # Текст для поиска на конкретном языке searchText = ( (searchFields.titles[index] or '') + " " + (searchFields.contents[index] or '') + " " + (searchFields.excerpts[index] or '') + " " + (searchFields.authors[index] or '') + " " + (searchFields.names?[index] or '') + " " + (searchFields.descriptions?[index] or '') ).toLowerCase() # Добавляем теги if searchFields.tags[index] searchText += " " + searchFields.tags[index].join(" ") words = searchText.split(/\W+/).filter (word) -> word.length > 2 for word in words emit([domain, language, word], { _id: doc._id type: searchFields.type title: searchFields.titles[index] excerpt: searchFields.excerpts[index] language: language domain: domain created_at: doc.created_at }) ).toString() # Поиск по конкретному типу контента by_content_type: map: ((doc) -> if doc.type in ['blog_post', 'event', 'product', 'slide'] and doc.status is 'published' domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default'] languages = doc.language or ['ru'] for domain in domains for language, index in languages emit([domain, doc.type, language, doc.created_at], { _id: doc._id title: doc.title?[index] excerpt: doc.excerpt?[index] image: doc.image?[index] author: doc.author?[index] language: language featured: doc.featured or false }) ).toString() # Design документ для работы с мультиязычными блог постами и наследниками multilingual_content: version: "6.0" views: # Все опубликованные документы контента по доменам и языкам published_by_domain_language: map: ((doc) -> if doc.type in ['blog_post', 'event', 'product', 'slide'] and doc.status is 'published' domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default'] languages = doc.language or ['ru'] for domain in domains for language, index in languages contentData = { _id: doc._id type: doc.type title: doc.title?[index] excerpt: doc.excerpt?[index] image: doc.image?[index] author: doc.author?[index] created_at: doc.created_at published_at: doc.published_at featured: doc.featured or false views: doc.views or 0 language: language domain: domain } # Добавляем специфичные поля для наследников switch doc.type when 'event' contentData.event_date = doc.event_data?.event_date contentData.location = doc.event_data?.location?[index] contentData.price = doc.event_data?.price?[index] contentData.status = doc.event_data?.status when 'product' contentData.price = doc.product_data?.price?[index] contentData.status = doc.product_data?.status contentData.inventory = doc.product_data?.inventory when 'slide' contentData.order = doc.slide_data?.order contentData.active = doc.slide_data?.active emit([domain, language, doc.created_at], contentData) ).toString() # Избранный контент с приоритетом featured_content: map: ((doc) -> if doc.type in ['blog_post', 'event', 'product', 'slide'] and doc.status is 'published' and doc.featured is true domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default'] languages = doc.language or ['ru'] for domain in domains for language, index in languages emit([domain, language, doc.featured, doc.created_at], { _id: doc._id type: doc.type title: doc.title?[index] excerpt: doc.excerpt?[index] image: doc.image?[index] language: language }) ).toString() # Контент по категориям с поддержкой иерархии by_category_path: map: ((doc) -> if doc.type in ['blog_post', 'event', 'product', 'slide'] and doc.status is 'published' and doc.category_path domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default'] languages = doc.language or ['ru'] for domain in domains for language, index in languages # Эмитим для каждой категории в пути for category_id in doc.category_path emit([domain, language, category_id, doc.created_at], { _id: doc._id type: doc.type title: doc.title?[index] category_id: doc.category_id language: language }) ).toString() # Design документ для событий (events) с мультиязычными данными events_multilingual: version: "6.0" views: # События по дате с мультиязычной информацией by_date_multilingual: map: ((doc) -> if doc.type is 'event' and doc.status is 'published' domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default'] languages = doc.language or ['ru'] event_date = doc.event_data?.event_date if event_date for domain in domains for language, index in languages emit([domain, language, event_date], { _id: doc._id title: doc.title?[index] excerpt: doc.excerpt?[index] location: doc.event_data?.location?[index] price: doc.event_data?.price?[index] available_tickets: doc.event_data?.available_tickets status: doc.event_data?.status image: doc.image?[index] language: language }) ).toString() # Предстоящие события upcoming_events: map: ((doc) -> if doc.type is 'event' and doc.event_data?.status is 'upcoming' domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default'] languages = doc.language or ['ru'] event_date = doc.event_data?.event_date if event_date for domain in domains for language, index in languages emit([domain, language, event_date], { _id: doc._id title: doc.title?[index] location: doc.event_data?.location?[index] price: doc.event_data?.price?[index] available_tickets: doc.event_data?.available_tickets image: doc.image?[index] language: language }) ).toString() # События по местоположению by_location_multilingual: map: ((doc) -> if doc.type is 'event' and doc.status is 'published' domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default'] languages = doc.language or ['ru'] locations = doc.event_data?.location or [] for domain in domains for language, index in languages location = locations[index] if location emit([domain, language, location, doc.event_data?.event_date], { _id: doc._id title: doc.title?[index] event_date: doc.event_data?.event_date price: doc.event_data?.price?[index] language: language }) ).toString() # Design документ для товаров (products) с мультиязычными данными products_multilingual: version: "6.0" views: # Товары по статусу и доступности by_status_multilingual: map: ((doc) -> if doc.type is 'product' and doc.status is 'published' domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default'] languages = doc.language or ['ru'] product_status = doc.product_data?.status for domain in domains for language, index in languages emit([domain, language, product_status, doc.created_at], { _id: doc._id title: doc.title?[index] price: doc.product_data?.price?[index] compare_price: doc.product_data?.compare_price?[index] inventory: doc.product_data?.inventory sku: doc.product_data?.sku image: doc.image?[index] language: language }) ).toString() # Товары по цене by_price_range: map: ((doc) -> if doc.type is 'product' and doc.status is 'published' and doc.product_data?.status is 'available' domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default'] languages = doc.language or ['ru'] prices = doc.product_data?.price or [] for domain in domains for language, index in languages price = prices[index] if price # Группируем по ценовым диапазонам price_range = Math.floor(price / 100) * 100 emit([domain, language, price_range, doc.created_at], { _id: doc._id title: doc.title?[index] price: price inventory: doc.product_data?.inventory image: doc.image?[index] language: language }) ).toString() # Товары по тегам by_tags_multilingual: map: ((doc) -> if doc.type is 'product' and doc.status is 'published' domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default'] languages = doc.language or ['ru'] tagsArrays = doc.tags or [] for domain in domains for language, index in languages tags = tagsArrays[index] or [] for tag in tags emit([domain, language, tag, doc.created_at], { _id: doc._id title: doc.title?[index] price: doc.product_data?.price?[index] image: doc.image?[index] language: language }) ).toString() # Design документ для слайдеров (slides) с мультиязычными данными slides_multilingual: version: "6.0" views: # Активные слайды по порядку active_ordered_multilingual: map: ((doc) -> if doc.type is 'slide' and doc.slide_data?.active is true domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default'] languages = doc.language or ['ru'] order = doc.slide_data?.order or 0 for domain in domains for language, index in languages emit([domain, language, order], { _id: doc._id title: doc.title?[index] content: doc.content?[index] image: doc.image?[index] button_text: doc.slide_data?.button_text?[index] button_link: doc.slide_data?.button_link?[index] language: language }) ).toString() # Слайды по датам активности by_active_dates: map: ((doc) -> if doc.type is 'slide' and doc.slide_data?.active is true domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default'] start_date = doc.slide_data?.start_date end_date = doc.slide_data?.end_date if start_date and end_date for domain in domains emit([domain, start_date, end_date], { _id: doc._id title: doc.title?[0] # Берем первый язык для ключа order: doc.slide_data?.order }) ).toString() # Design документ для иерархических категорий с мультиязычностью categories_hierarchical_multilingual: version: "6.0" views: # Категории по уровню иерархии by_level_multilingual: map: ((doc) -> if doc.type is 'category' domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default'] languages = doc.language or ['ru'] level = doc.level or 0 for domain in domains for language, index in languages emit([domain, language, level, doc.order], { _id: doc._id name: doc.name?[index] slug: doc.slug?[index] description: doc.description?[index] parent_id: doc.parent_id level: level order: doc.order active: doc.active featured: doc.featured show_in_menu: doc.show_in_menu language: language }) ).toString() # Категории по родителю для построения дерева by_parent_multilingual: map: ((doc) -> if doc.type is 'category' domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default'] languages = doc.language or ['ru'] parent_id = doc.parent_id or 'root' for domain in domains for language, index in languages emit([domain, language, parent_id, doc.order], { _id: doc._id name: doc.name?[index] slug: doc.slug?[index] level: doc.level children_count: doc.children_count order: doc.order active: doc.active language: language }) ).toString() # Корневые категории root_categories_multilingual: map: ((doc) -> if doc.type is 'category' and (not doc.parent_id or doc.parent_id is null) domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default'] languages = doc.language or ['ru'] for domain in domains for language, index in languages emit([domain, language, doc.order], { _id: doc._id name: doc.name?[index] slug: doc.slug?[index] level: 0 children_count: doc.children_count order: doc.order active: doc.active featured: doc.featured language: language }) ).toString() # Design документ для статистики и аналитики мультиязычного контента multilingual_statistics: version: "6.0" views: # Статистика по типам контента и языкам content_stats_by_language: map: ((doc) -> if doc.type in ['blog_post', 'event', 'product', 'slide'] and doc.status is 'published' domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default'] languages = doc.language or ['ru'] for domain in domains for language in languages # Статистика по типам emit([domain, 'type_count', doc.type, language], 1) # Статистика по датам if doc.created_at date = doc.created_at.split('T')[0] emit([domain, 'creation_date', date, language], 1) # Статистика просмотров if doc.views emit([domain, 'views', doc.type, language], doc.views) ).toString() reduce: ((keys, values) -> sum values ).toString() # Статистика популярности контента content_popularity_multilingual: map: ((doc) -> if doc.type is 'blog_post' domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default'] languages = doc.language or ['ru'] views = doc.views or 0 likes = doc.likes or 0 shares = doc.shares or 0 popularity = views + (likes * 2) + (shares * 3) for domain in domains for language in languages emit([domain, language, popularity], { _id: doc._id type: doc.type title: doc.title?[0] # Первый язык для ключа views: views likes: likes shares: shares popularity: popularity }) else if doc.type is 'event' domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default'] languages = doc.language or ['ru'] tickets_sold = (doc.event_data?.total_tickets or 0) - (doc.event_data?.available_tickets or 0) for domain in domains for language in languages emit([domain, language, tickets_sold], { _id: doc._id type: doc.type title: doc.title?[0] tickets_sold: tickets_sold total_tickets: doc.event_data?.total_tickets }) ).toString() # Design документ для работы с заказами orders_management: version: "6.0" views: # Заказы по статусу и домену by_status_and_domain: map: ((doc) -> if doc.type is 'order' domain = doc.domain or 'default' languages = doc.language or ['ru'] for language in languages emit([domain, language, doc.status, doc.created_at], { _id: doc._id total: doc.total currency: doc.currency customer_name: doc.customer_info?.name?[0] # Первый язык created_at: doc.created_at items_count: doc.items?.length or 0 }) ).toString() # Статистика продаж по доменам и языкам sales_statistics_multilingual: map: ((doc) -> if doc.type is 'order' and doc.status is 'completed' domain = doc.domain or 'default' languages = doc.language or ['ru'] date = doc.created_at.split('T')[0] for language in languages # Общая сумма за день emit([domain, language, 'daily_sales', date], doc.total) # Количество заказов за день emit([domain, language, 'daily_orders', date], 1) # Статистика по товарам if doc.items for item in doc.items emit([domain, language, 'product_sales', item.product_id], item.quantity) emit([domain, language, 'product_revenue', item.product_id], item.total) ).toString() reduce: ((keys, values) -> sum values ).toString() # Design документ для пользователей и управления доступом users_management: version: "6.0" views: # Пользователи по email и роли by_email_and_role: map: ((doc) -> if doc.type is 'user' emit([doc.email, doc.role], { _id: doc._id name: doc.name?[0] # Первый язык active: doc.active last_login: doc.last_login domains_access: doc.domains_access }) ).toString() # Активные пользователи по доменам active_users_by_domain: map: ((doc) -> if doc.type is 'user' and doc.active is true domains = doc.domains_access or [] for domain in domains emit([domain, doc.role, doc.email], { _id: doc._id name: doc.name?[0] email: doc.email last_login: doc.last_login }) ).toString() # Design документ для системы уведомлений с мультиязычностью multilingual_notifications: version: "6.0" views: # Уведомления о предстоящих событиях event_reminders_multilingual: map: ((doc) -> if doc.type is 'event' and doc.event_data?.status is 'upcoming' domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default'] languages = doc.language or ['ru'] event_date = new Date(doc.event_data.event_date) now = new Date() # Уведомление за 7 дней до события sevenDaysBefore = new Date(event_date.getTime() - 7 * 24 * 60 * 60 * 1000) if now >= sevenDaysBefore and now < event_date for domain in domains for language, index in languages emit([domain, language, 'event_reminder_7d', doc.event_data.event_date], { _id: doc._id title: doc.title?[index] event_date: doc.event_data.event_date domain: domain language: language notification_type: 'event_reminder_7d' }) # Уведомление за 1 день до события oneDayBefore = new Date(event_date.getTime() - 24 * 60 * 60 * 1000) if now >= oneDayBefore and now < event_date for domain in domains for language, index in languages emit([domain, language, 'event_reminder_1d', doc.event_data.event_date], { _id: doc._id title: doc.title?[index] event_date: doc.event_data.event_date domain: domain language: language notification_type: 'event_reminder_1d' }) ).toString() # Уведомления о низком количестве товаров low_inventory_alerts: map: ((doc) -> if doc.type is 'product' and doc.product_data?.inventory < 10 domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default'] languages = doc.language or ['ru'] for domain in domains for language, index in languages emit([domain, language, 'low_inventory', doc.product_data.inventory], { _id: doc._id title: doc.title?[index] inventory: doc.product_data.inventory sku: doc.product_data.sku domain: domain language: language notification_type: 'low_inventory' }) ).toString()