|
@@ -1,438 +1,644 @@
|
|
|
-# Design документы для CouchDB с поддержкой иерархических категорий
|
|
|
|
|
-# Версия 5.0 - с иерархической структурой категорий
|
|
|
|
|
|
|
+# Design документы для CouchDB с поддержкой мультиязычных массивов и наследования
|
|
|
|
|
+# Версия 6.0 - унифицированная структура данных
|
|
|
|
|
|
|
|
module.exports =
|
|
module.exports =
|
|
|
- # Design документ для работы с иерархическими категориями
|
|
|
|
|
- categories_hierarchical:
|
|
|
|
|
- version: "5.0"
|
|
|
|
|
|
|
+ # Design документ для универсального поиска по мультиязычному контенту
|
|
|
|
|
+ universal_multilingual_search:
|
|
|
|
|
+ version: "6.0"
|
|
|
views:
|
|
views:
|
|
|
- # Все категории по уровню иерархии
|
|
|
|
|
- by_level:
|
|
|
|
|
|
|
+ # Универсальный поиск по всем типам контента с поддержкой массивов
|
|
|
|
|
+ content_search:
|
|
|
map: ((doc) ->
|
|
map: ((doc) ->
|
|
|
- if doc.type is 'category'
|
|
|
|
|
- domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default']
|
|
|
|
|
- level = doc.level or 0
|
|
|
|
|
|
|
+ # Пропускаем системные документы
|
|
|
|
|
+ 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 domain in domains
|
|
|
- emit([domain, level, doc.order], {
|
|
|
|
|
- _id: doc._id
|
|
|
|
|
- name: doc.name
|
|
|
|
|
- slug: doc.slug
|
|
|
|
|
- parent_id: doc.parent_id
|
|
|
|
|
- level: level
|
|
|
|
|
- order: doc.order
|
|
|
|
|
- active: doc.active
|
|
|
|
|
- featured: doc.featured
|
|
|
|
|
- show_in_menu: doc.show_in_menu
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ 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()
|
|
).toString()
|
|
|
-
|
|
|
|
|
- # Категории по родителю (для построения дерева)
|
|
|
|
|
- by_parent:
|
|
|
|
|
|
|
+
|
|
|
|
|
+ # Поиск по конкретному типу контента
|
|
|
|
|
+ by_content_type:
|
|
|
map: ((doc) ->
|
|
map: ((doc) ->
|
|
|
- if doc.type is 'category'
|
|
|
|
|
|
|
+ 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']
|
|
domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default']
|
|
|
- parent_id = doc.parent_id or 'root'
|
|
|
|
|
|
|
+ languages = doc.language or ['ru']
|
|
|
|
|
|
|
|
for domain in domains
|
|
for domain in domains
|
|
|
- emit([domain, parent_id, doc.order], {
|
|
|
|
|
- _id: doc._id
|
|
|
|
|
- name: doc.name
|
|
|
|
|
- slug: doc.slug
|
|
|
|
|
- level: doc.level
|
|
|
|
|
- children_count: doc.children_count
|
|
|
|
|
- order: doc.order
|
|
|
|
|
- active: doc.active
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ 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()
|
|
).toString()
|
|
|
-
|
|
|
|
|
- # Полное дерево категорий с путями
|
|
|
|
|
- by_path:
|
|
|
|
|
|
|
+
|
|
|
|
|
+ # Design документ для работы с мультиязычными блог постами и наследниками
|
|
|
|
|
+ multilingual_content:
|
|
|
|
|
+ version: "6.0"
|
|
|
|
|
+ views:
|
|
|
|
|
+ # Все опубликованные документы контента по доменам и языкам
|
|
|
|
|
+ published_by_domain_language:
|
|
|
map: ((doc) ->
|
|
map: ((doc) ->
|
|
|
- if doc.type is 'category'
|
|
|
|
|
|
|
+ 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']
|
|
domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default']
|
|
|
- parent_path = doc.parent_path or []
|
|
|
|
|
|
|
+ languages = doc.language or ['ru']
|
|
|
|
|
|
|
|
for domain in domains
|
|
for domain in domains
|
|
|
- # Эмитим каждый сегмент пути для быстрого поиска
|
|
|
|
|
- for path_segment, index in parent_path
|
|
|
|
|
- emit([domain, path_segment, doc.level, doc.order], doc)
|
|
|
|
|
-
|
|
|
|
|
- # Эмитим саму категорию
|
|
|
|
|
- emit([domain, doc._id, doc.level, doc.order], doc)
|
|
|
|
|
|
|
+ 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()
|
|
).toString()
|
|
|
-
|
|
|
|
|
- # Корневые категории
|
|
|
|
|
- root_categories:
|
|
|
|
|
|
|
+
|
|
|
|
|
+ # Избранный контент с приоритетом
|
|
|
|
|
+ featured_content:
|
|
|
map: ((doc) ->
|
|
map: ((doc) ->
|
|
|
- if doc.type is 'category' and (not doc.parent_id or doc.parent_id is null)
|
|
|
|
|
|
|
+ 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']
|
|
domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default']
|
|
|
|
|
+ languages = doc.language or ['ru']
|
|
|
|
|
|
|
|
for domain in domains
|
|
for domain in domains
|
|
|
- emit([domain, doc.order], {
|
|
|
|
|
- _id: doc._id
|
|
|
|
|
- name: doc.name
|
|
|
|
|
- slug: doc.slug
|
|
|
|
|
- level: 0
|
|
|
|
|
- children_count: doc.children_count
|
|
|
|
|
- order: doc.order
|
|
|
|
|
- active: doc.active
|
|
|
|
|
- featured: doc.featured
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ 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()
|
|
).toString()
|
|
|
-
|
|
|
|
|
- # Категории для меню
|
|
|
|
|
- menu_categories:
|
|
|
|
|
|
|
+
|
|
|
|
|
+ # Контент по категориям с поддержкой иерархии
|
|
|
|
|
+ by_category_path:
|
|
|
map: ((doc) ->
|
|
map: ((doc) ->
|
|
|
- if doc.type is 'category' and doc.show_in_menu is true
|
|
|
|
|
|
|
+ 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']
|
|
domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default']
|
|
|
- level = doc.level or 0
|
|
|
|
|
|
|
+ languages = doc.language or ['ru']
|
|
|
|
|
|
|
|
for domain in domains
|
|
for domain in domains
|
|
|
- emit([domain, level, doc.menu_order or doc.order], {
|
|
|
|
|
- _id: doc._id
|
|
|
|
|
- name: doc.name
|
|
|
|
|
- slug: doc.slug
|
|
|
|
|
- parent_id: doc.parent_id
|
|
|
|
|
- level: level
|
|
|
|
|
- menu_order: doc.menu_order
|
|
|
|
|
- icon: doc.icon
|
|
|
|
|
- color: doc.color
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ 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()
|
|
).toString()
|
|
|
|
|
|
|
|
- # Design документ для контента с иерархическими категориями
|
|
|
|
|
- content_with_hierarchical_categories:
|
|
|
|
|
- version: "5.0"
|
|
|
|
|
|
|
+ # Design документ для событий (events) с мультиязычными данными
|
|
|
|
|
+ events_multilingual:
|
|
|
|
|
+ version: "6.0"
|
|
|
views:
|
|
views:
|
|
|
- # Контент по полному пути категории
|
|
|
|
|
- by_category_path:
|
|
|
|
|
|
|
+ # События по дате с мультиязычной информацией
|
|
|
|
|
+ by_date_multilingual:
|
|
|
map: ((doc) ->
|
|
map: ((doc) ->
|
|
|
- if (doc.type is 'blog_post' or doc.type is 'event') and doc.category_path
|
|
|
|
|
|
|
+ if doc.type is 'event' and doc.status is 'published'
|
|
|
domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default']
|
|
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
|
|
|
|
|
|
|
|
- for domain in domains
|
|
|
|
|
- # Эмитим для каждого сегмента пути категории
|
|
|
|
|
- for category_id in doc.category_path
|
|
|
|
|
- emit([domain, category_id, doc.created_at], {
|
|
|
|
|
- _id: doc._id
|
|
|
|
|
- type: doc.type
|
|
|
|
|
- title: doc.title
|
|
|
|
|
- category_id: doc.category_id
|
|
|
|
|
- category_path: doc.category_path
|
|
|
|
|
- created_at: doc.created_at
|
|
|
|
|
- status: doc.status
|
|
|
|
|
- featured: doc.featured
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ 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()
|
|
).toString()
|
|
|
-
|
|
|
|
|
- # Контент по конечной категории (самой глубокой)
|
|
|
|
|
- by_leaf_category:
|
|
|
|
|
|
|
+
|
|
|
|
|
+ # Предстоящие события
|
|
|
|
|
+ upcoming_events:
|
|
|
map: ((doc) ->
|
|
map: ((doc) ->
|
|
|
- if (doc.type is 'blog_post' or doc.type is 'event') and doc.category_path
|
|
|
|
|
|
|
+ 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']
|
|
domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default']
|
|
|
- leaf_category = doc.category_path[doc.category_path.length - 1]
|
|
|
|
|
|
|
+ languages = doc.language or ['ru']
|
|
|
|
|
+ event_date = doc.event_data?.event_date
|
|
|
|
|
|
|
|
- for domain in domains
|
|
|
|
|
- emit([domain, leaf_category, doc.created_at], {
|
|
|
|
|
- _id: doc._id
|
|
|
|
|
- type: doc.type
|
|
|
|
|
- title: doc.title
|
|
|
|
|
- category_id: doc.category_id
|
|
|
|
|
- created_at: doc.created_at
|
|
|
|
|
- status: doc.status
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ 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()
|
|
).toString()
|
|
|
-
|
|
|
|
|
- # Контент по корневой категории
|
|
|
|
|
- by_root_category:
|
|
|
|
|
|
|
+
|
|
|
|
|
+ # События по местоположению
|
|
|
|
|
+ by_location_multilingual:
|
|
|
map: ((doc) ->
|
|
map: ((doc) ->
|
|
|
- if (doc.type is 'blog_post' or doc.type is 'event') and doc.category_path
|
|
|
|
|
|
|
+ if doc.type is 'event' and doc.status is 'published'
|
|
|
domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default']
|
|
domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default']
|
|
|
- root_category = doc.category_path[0]
|
|
|
|
|
|
|
+ languages = doc.language or ['ru']
|
|
|
|
|
+ locations = doc.event_data?.location or []
|
|
|
|
|
|
|
|
for domain in domains
|
|
for domain in domains
|
|
|
- emit([domain, root_category, doc.created_at], {
|
|
|
|
|
- _id: doc._id
|
|
|
|
|
- type: doc.type
|
|
|
|
|
- title: doc.title
|
|
|
|
|
- root_category: root_category
|
|
|
|
|
- created_at: doc.created_at
|
|
|
|
|
- status: doc.status
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ 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()
|
|
).toString()
|
|
|
|
|
|
|
|
- # Design документ для поиска с учетом иерархии категорий
|
|
|
|
|
- search_with_category_hierarchy:
|
|
|
|
|
- version: "5.0"
|
|
|
|
|
|
|
+ # Design документ для товаров (products) с мультиязычными данными
|
|
|
|
|
+ products_multilingual:
|
|
|
|
|
+ version: "6.0"
|
|
|
views:
|
|
views:
|
|
|
- # Поиск по контенту с информацией о категории
|
|
|
|
|
- content_with_category_info:
|
|
|
|
|
|
|
+ # Товары по статусу и доступности
|
|
|
|
|
+ by_status_multilingual:
|
|
|
map: ((doc) ->
|
|
map: ((doc) ->
|
|
|
- if (doc.type is 'blog_post' and doc.status is 'published') or doc.type is 'event'
|
|
|
|
|
|
|
+ if doc.type is 'product' and doc.status is 'published'
|
|
|
domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default']
|
|
domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default']
|
|
|
-
|
|
|
|
|
- search_text = (doc.title + " " + (doc.content or "") + " " + (doc.excerpt or "")).toLowerCase()
|
|
|
|
|
- words = search_text.split(/\W+/).filter (word) -> word.length > 2
|
|
|
|
|
|
|
+ languages = doc.language or ['ru']
|
|
|
|
|
+ product_status = doc.product_data?.status
|
|
|
|
|
|
|
|
for domain in domains
|
|
for domain in domains
|
|
|
- for word in words
|
|
|
|
|
- emit([domain, word], {
|
|
|
|
|
|
|
+ for language, index in languages
|
|
|
|
|
+ emit([domain, language, product_status, doc.created_at], {
|
|
|
_id: doc._id
|
|
_id: doc._id
|
|
|
- type: doc.type
|
|
|
|
|
- title: doc.title
|
|
|
|
|
- excerpt: doc.excerpt
|
|
|
|
|
- category_id: doc.category_id
|
|
|
|
|
- category_path: doc.category_path
|
|
|
|
|
- created_at: doc.created_at
|
|
|
|
|
- domain: domain
|
|
|
|
|
|
|
+ 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()
|
|
).toString()
|
|
|
-
|
|
|
|
|
- # Поиск по категориям и тегам
|
|
|
|
|
- by_category_and_tags:
|
|
|
|
|
|
|
+
|
|
|
|
|
+ # Товары по цене
|
|
|
|
|
+ by_price_range:
|
|
|
map: ((doc) ->
|
|
map: ((doc) ->
|
|
|
- if (doc.type is 'blog_post' and doc.status is 'published') or doc.type is 'event'
|
|
|
|
|
|
|
+ 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']
|
|
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 domain in domains
|
|
|
- # По категории
|
|
|
|
|
- if doc.category_id
|
|
|
|
|
- emit([domain, 'category', doc.category_id, doc.created_at], {
|
|
|
|
|
- _id: doc._id
|
|
|
|
|
- type: doc.type
|
|
|
|
|
- title: doc.title
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- # По тегам
|
|
|
|
|
- if doc.tags
|
|
|
|
|
- for tag in doc.tags
|
|
|
|
|
- emit([domain, 'tag', tag, doc.created_at], {
|
|
|
|
|
|
|
+ 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
|
|
_id: doc._id
|
|
|
- type: doc.type
|
|
|
|
|
- title: doc.title
|
|
|
|
|
|
|
+ title: doc.title?[index]
|
|
|
|
|
+ price: price
|
|
|
|
|
+ inventory: doc.product_data?.inventory
|
|
|
|
|
+ image: doc.image?[index]
|
|
|
|
|
+ language: language
|
|
|
})
|
|
})
|
|
|
).toString()
|
|
).toString()
|
|
|
|
|
|
|
|
- # Design документ для статистики иерархических категорий
|
|
|
|
|
- category_statistics:
|
|
|
|
|
- version: "5.0"
|
|
|
|
|
- views:
|
|
|
|
|
- # Статистика контента по категориям
|
|
|
|
|
- content_count_by_category:
|
|
|
|
|
|
|
+ # Товары по тегам
|
|
|
|
|
+ by_tags_multilingual:
|
|
|
map: ((doc) ->
|
|
map: ((doc) ->
|
|
|
- if (doc.type is 'blog_post' or doc.type is 'event') and doc.category_id
|
|
|
|
|
|
|
+ if doc.type is 'product' and doc.status is 'published'
|
|
|
domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default']
|
|
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 domain in domains
|
|
|
- # По конечной категории
|
|
|
|
|
- emit([domain, 'leaf_category', doc.category_id, doc.type], 1)
|
|
|
|
|
-
|
|
|
|
|
- # По всем категориям в пути
|
|
|
|
|
- if doc.category_path
|
|
|
|
|
- for category_id in doc.category_path
|
|
|
|
|
- emit([domain, 'path_category', category_id, doc.type], 1)
|
|
|
|
|
- ).toString()
|
|
|
|
|
- reduce: ((keys, values) ->
|
|
|
|
|
- sum values
|
|
|
|
|
|
|
+ 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()
|
|
).toString()
|
|
|
-
|
|
|
|
|
- # Статистика популярности категорий
|
|
|
|
|
- category_popularity:
|
|
|
|
|
|
|
+
|
|
|
|
|
+ # Design документ для слайдеров (slides) с мультиязычными данными
|
|
|
|
|
+ slides_multilingual:
|
|
|
|
|
+ version: "6.0"
|
|
|
|
|
+ views:
|
|
|
|
|
+ # Активные слайды по порядку
|
|
|
|
|
+ active_ordered_multilingual:
|
|
|
map: ((doc) ->
|
|
map: ((doc) ->
|
|
|
- if doc.type is 'blog_post'
|
|
|
|
|
|
|
+ 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']
|
|
domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default']
|
|
|
- views = doc.views or 0
|
|
|
|
|
|
|
+ languages = doc.language or ['ru']
|
|
|
|
|
+ order = doc.slide_data?.order or 0
|
|
|
|
|
|
|
|
for domain in domains
|
|
for domain in domains
|
|
|
- if doc.category_id
|
|
|
|
|
- emit([domain, doc.category_id], views)
|
|
|
|
|
-
|
|
|
|
|
- if doc.category_path
|
|
|
|
|
- for category_id in doc.category_path
|
|
|
|
|
- emit([domain, category_id], views)
|
|
|
|
|
- else if doc.type is 'event'
|
|
|
|
|
|
|
+ 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']
|
|
domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default']
|
|
|
- tickets_sold = (doc.total_tickets or 0) - (doc.available_tickets or 0)
|
|
|
|
|
|
|
+ start_date = doc.slide_data?.start_date
|
|
|
|
|
+ end_date = doc.slide_data?.end_date
|
|
|
|
|
|
|
|
- for domain in domains
|
|
|
|
|
- if doc.category_id
|
|
|
|
|
- emit([domain, doc.category_id], tickets_sold)
|
|
|
|
|
- ).toString()
|
|
|
|
|
- reduce: ((keys, values) ->
|
|
|
|
|
- sum values
|
|
|
|
|
|
|
+ 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()
|
|
).toString()
|
|
|
|
|
|
|
|
- # Design документ для навигации по иерархии
|
|
|
|
|
- category_navigation:
|
|
|
|
|
- version: "5.0"
|
|
|
|
|
|
|
+ # Design документ для иерархических категорий с мультиязычностью
|
|
|
|
|
+ categories_hierarchical_multilingual:
|
|
|
|
|
+ version: "6.0"
|
|
|
views:
|
|
views:
|
|
|
- # Соседние категории (одного уровня)
|
|
|
|
|
- siblings_categories:
|
|
|
|
|
|
|
+ # Категории по уровню иерархии
|
|
|
|
|
+ by_level_multilingual:
|
|
|
map: ((doc) ->
|
|
map: ((doc) ->
|
|
|
if doc.type is 'category'
|
|
if doc.type is 'category'
|
|
|
domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default']
|
|
domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default']
|
|
|
- parent_id = doc.parent_id or 'root'
|
|
|
|
|
|
|
+ languages = doc.language or ['ru']
|
|
|
|
|
+ level = doc.level or 0
|
|
|
|
|
|
|
|
for domain in domains
|
|
for domain in domains
|
|
|
- emit([domain, parent_id, doc.order], {
|
|
|
|
|
- _id: doc._id
|
|
|
|
|
- name: doc.name
|
|
|
|
|
- slug: doc.slug
|
|
|
|
|
- order: doc.order
|
|
|
|
|
- level: doc.level
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ 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()
|
|
).toString()
|
|
|
-
|
|
|
|
|
- # Дочерние категории
|
|
|
|
|
- children_categories:
|
|
|
|
|
|
|
+
|
|
|
|
|
+ # Категории по родителю для построения дерева
|
|
|
|
|
+ by_parent_multilingual:
|
|
|
map: ((doc) ->
|
|
map: ((doc) ->
|
|
|
if doc.type is 'category'
|
|
if doc.type is 'category'
|
|
|
domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default']
|
|
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 domain in domains
|
|
|
- emit([domain, doc._id, 'children'], {
|
|
|
|
|
- _id: doc._id
|
|
|
|
|
- name: doc.name
|
|
|
|
|
- children_count: doc.children_count
|
|
|
|
|
- has_children: doc.children_count > 0
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ 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()
|
|
).toString()
|
|
|
-
|
|
|
|
|
- # Хлебные крошки для категорий
|
|
|
|
|
- breadcrumbs:
|
|
|
|
|
|
|
+
|
|
|
|
|
+ # Корневые категории
|
|
|
|
|
+ root_categories_multilingual:
|
|
|
map: ((doc) ->
|
|
map: ((doc) ->
|
|
|
- if doc.type is 'category' and doc.parent_path
|
|
|
|
|
|
|
+ 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']
|
|
domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default']
|
|
|
|
|
+ languages = doc.language or ['ru']
|
|
|
|
|
|
|
|
for domain in domains
|
|
for domain in domains
|
|
|
- # Эмитим для каждого родителя в пути
|
|
|
|
|
- for parent_id, index in doc.parent_path
|
|
|
|
|
- emit([domain, doc._id, 'parent', index], {
|
|
|
|
|
- parent_id: parent_id
|
|
|
|
|
- position: index
|
|
|
|
|
- current_category: doc._id
|
|
|
|
|
|
|
+ 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()
|
|
).toString()
|
|
|
|
|
|
|
|
- # Design документ для мультидоменного поиска (обновленный)
|
|
|
|
|
- multi_domain_search:
|
|
|
|
|
- version: "5.0"
|
|
|
|
|
|
|
+ # Design документ для статистики и аналитики мультиязычного контента
|
|
|
|
|
+ multilingual_statistics:
|
|
|
|
|
+ version: "6.0"
|
|
|
views:
|
|
views:
|
|
|
- # Универсальный поиск с учетом иерархии категорий
|
|
|
|
|
- universal_search_with_categories:
|
|
|
|
|
|
|
+ # Статистика по типам контента и языкам
|
|
|
|
|
+ content_stats_by_language:
|
|
|
map: ((doc) ->
|
|
map: ((doc) ->
|
|
|
- if doc._id.startsWith('_design/') or doc.type is 'domain_settings'
|
|
|
|
|
- return
|
|
|
|
|
-
|
|
|
|
|
- domain = doc.domain or 'default'
|
|
|
|
|
- domains = if Array.isArray(domain) then domain else [domain]
|
|
|
|
|
- language = doc.language or 'ru'
|
|
|
|
|
-
|
|
|
|
|
- searchFields = {}
|
|
|
|
|
- searchText = ""
|
|
|
|
|
-
|
|
|
|
|
- switch doc.type
|
|
|
|
|
- when 'blog_post'
|
|
|
|
|
- if doc.status is 'published'
|
|
|
|
|
- searchFields =
|
|
|
|
|
- title: doc.title
|
|
|
|
|
- content: doc.content
|
|
|
|
|
- excerpt: doc.excerpt
|
|
|
|
|
- author: doc.author
|
|
|
|
|
- tags: doc.tags
|
|
|
|
|
- category_path: doc.category_path
|
|
|
|
|
- type: 'blog_post'
|
|
|
|
|
|
|
+ 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']
|
|
|
|
|
|
|
|
- when 'event'
|
|
|
|
|
- searchFields =
|
|
|
|
|
- title: doc.title
|
|
|
|
|
- content: doc.content
|
|
|
|
|
- location: doc.location
|
|
|
|
|
- tags: doc.tags
|
|
|
|
|
- category_path: doc.category_path
|
|
|
|
|
- type: 'event'
|
|
|
|
|
-
|
|
|
|
|
- if searchFields.title
|
|
|
|
|
- text = (
|
|
|
|
|
- searchFields.title + " " +
|
|
|
|
|
- (searchFields.content or "") + " " +
|
|
|
|
|
- (searchFields.excerpt or "") + " " +
|
|
|
|
|
- (searchFields.author or "") + " " +
|
|
|
|
|
- (searchFields.location or "")
|
|
|
|
|
- ).toLowerCase()
|
|
|
|
|
|
|
+ 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
|
|
|
|
|
|
|
|
- if searchFields.tags
|
|
|
|
|
- text += " " + searchFields.tags.join(" ")
|
|
|
|
|
|
|
+ popularity = views + (likes * 2) + (shares * 3)
|
|
|
|
|
|
|
|
- words = text.split(/\W+/).filter (word) -> word.length > 2
|
|
|
|
|
|
|
+ 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 domain in domains
|
|
|
- for word in words
|
|
|
|
|
- emit([domain, language, word], {
|
|
|
|
|
|
|
+ for language in languages
|
|
|
|
|
+ emit([domain, language, tickets_sold], {
|
|
|
_id: doc._id
|
|
_id: doc._id
|
|
|
- type: searchFields.type
|
|
|
|
|
- title: searchFields.title
|
|
|
|
|
- excerpt: searchFields.excerpt
|
|
|
|
|
- category_path: searchFields.category_path
|
|
|
|
|
- created_at: doc.created_at
|
|
|
|
|
- domain: domain
|
|
|
|
|
- language: language
|
|
|
|
|
|
|
+ type: doc.type
|
|
|
|
|
+ title: doc.title?[0]
|
|
|
|
|
+ tickets_sold: tickets_sold
|
|
|
|
|
+ total_tickets: doc.event_data?.total_tickets
|
|
|
})
|
|
})
|
|
|
).toString()
|
|
).toString()
|
|
|
|
|
|
|
|
- # Design документ для блог постов (обновленный)
|
|
|
|
|
- blog_posts:
|
|
|
|
|
- version: "5.0"
|
|
|
|
|
|
|
+ # Design документ для работы с заказами
|
|
|
|
|
+ orders_management:
|
|
|
|
|
+ version: "6.0"
|
|
|
views:
|
|
views:
|
|
|
- # Блог посты с информацией о категориях
|
|
|
|
|
- published_with_categories:
|
|
|
|
|
|
|
+ # Заказы по статусу и домену
|
|
|
|
|
+ by_status_and_domain:
|
|
|
map: ((doc) ->
|
|
map: ((doc) ->
|
|
|
- if doc.type is 'blog_post' and doc.status is 'published'
|
|
|
|
|
- domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default']
|
|
|
|
|
- language = doc.language or 'ru'
|
|
|
|
|
|
|
+ if doc.type is 'order'
|
|
|
|
|
+ domain = doc.domain or 'default'
|
|
|
|
|
+ languages = doc.language or ['ru']
|
|
|
|
|
|
|
|
- for domain in domains
|
|
|
|
|
- emit([domain, language, doc.created_at], {
|
|
|
|
|
|
|
+ for language in languages
|
|
|
|
|
+ emit([domain, language, doc.status, doc.created_at], {
|
|
|
_id: doc._id
|
|
_id: doc._id
|
|
|
- title: doc.title
|
|
|
|
|
- excerpt: doc.excerpt
|
|
|
|
|
- image: doc.image
|
|
|
|
|
- author: doc.author
|
|
|
|
|
- category_id: doc.category_id
|
|
|
|
|
- category_path: doc.category_path
|
|
|
|
|
|
|
+ total: doc.total
|
|
|
|
|
+ currency: doc.currency
|
|
|
|
|
+ customer_name: doc.customer_info?.name?[0] # Первый язык
|
|
|
created_at: doc.created_at
|
|
created_at: doc.created_at
|
|
|
- domain: domain
|
|
|
|
|
- language: language
|
|
|
|
|
- featured: doc.featured or false
|
|
|
|
|
- views: doc.views or 0
|
|
|
|
|
|
|
+ items_count: doc.items?.length or 0
|
|
|
})
|
|
})
|
|
|
).toString()
|
|
).toString()
|
|
|
|
|
|
|
|
- # Design документ для мероприятий (обновленный)
|
|
|
|
|
- events:
|
|
|
|
|
- version: "5.0"
|
|
|
|
|
- views:
|
|
|
|
|
- # Мероприятия с информацией о категориях
|
|
|
|
|
- by_date_with_categories:
|
|
|
|
|
|
|
+ # Статистика продаж по доменам и языкам
|
|
|
|
|
+ sales_statistics_multilingual:
|
|
|
map: ((doc) ->
|
|
map: ((doc) ->
|
|
|
- if doc.type is 'event'
|
|
|
|
|
- domains = if Array.isArray(doc.domain) then doc.domain else [doc.domain or 'default']
|
|
|
|
|
- language = doc.language or 'ru'
|
|
|
|
|
|
|
+ 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
|
|
for domain in domains
|
|
|
- emit([domain, language, doc.event_date], {
|
|
|
|
|
|
|
+ emit([domain, doc.role, doc.email], {
|
|
|
_id: doc._id
|
|
_id: doc._id
|
|
|
- title: doc.title
|
|
|
|
|
- event_date: doc.event_date
|
|
|
|
|
- location: doc.location
|
|
|
|
|
- price: doc.price
|
|
|
|
|
- status: doc.status
|
|
|
|
|
- image: doc.image
|
|
|
|
|
- category_id: doc.category_id
|
|
|
|
|
- category_path: doc.category_path
|
|
|
|
|
- domain: domain
|
|
|
|
|
- language: language
|
|
|
|
|
- available_tickets: doc.available_tickets
|
|
|
|
|
|
|
+ name: doc.name?[0]
|
|
|
|
|
+ email: doc.email
|
|
|
|
|
+ last_login: doc.last_login
|
|
|
})
|
|
})
|
|
|
).toString()
|
|
).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()
|