|
@@ -1,644 +1,408 @@
|
|
|
-# Design документы для CouchDB с поддержкой мультиязычных массивов и наследования
|
|
|
|
|
-# Версия 6.0 - унифицированная структура данных
|
|
|
|
|
-
|
|
|
|
|
-module.exports =
|
|
|
|
|
- # Design документ для универсального поиска по мультиязычному контенту
|
|
|
|
|
- universal_multilingual_search:
|
|
|
|
|
- version: "6.0"
|
|
|
|
|
|
|
+# Design документ для универсальной CMS
|
|
|
|
|
+design_documents =
|
|
|
|
|
+ # Design документ для блог постов
|
|
|
|
|
+ blog_posts:
|
|
|
|
|
+ version: "1.2"
|
|
|
views:
|
|
views:
|
|
|
- # Универсальный поиск по всем типам контента с поддержкой массивов
|
|
|
|
|
- content_search:
|
|
|
|
|
|
|
+ # Все опубликованные блог посты
|
|
|
|
|
+ published:
|
|
|
map: ((doc) ->
|
|
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()
|
|
|
|
|
|
|
+ if doc.type is 'blog_post' and doc.status is 'published'
|
|
|
|
|
+ emit(doc.created_at, doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Блог посты по домену и языку
|
|
|
|
|
+ by_domain_language:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'blog_post' and doc.status is 'published' and doc.domain and doc.language
|
|
|
|
|
+ for domain in doc.domain
|
|
|
|
|
+ for lang in doc.language
|
|
|
|
|
+ emit([domain, lang, doc.created_at], doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Избранные блог посты
|
|
|
|
|
+ featured:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'blog_post' and doc.status is 'published' and doc.featured
|
|
|
|
|
+ emit(doc.created_at, doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Блог посты по категории
|
|
|
|
|
+ by_category:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'blog_post' and doc.status is 'published' and doc.category_id
|
|
|
|
|
+ emit([doc.category_id, doc.created_at], doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Блог посты по тегам
|
|
|
|
|
+ by_tags:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'blog_post' and doc.status is 'published' and doc.tags
|
|
|
|
|
+ for tag_array, lang_index in doc.tags
|
|
|
|
|
+ for tag in tag_array
|
|
|
|
|
+ emit([tag, doc.created_at], doc)).toString()
|
|
|
|
|
|
|
|
- # Design документ для работы с мультиязычными блог постами и наследниками
|
|
|
|
|
- multilingual_content:
|
|
|
|
|
- version: "6.0"
|
|
|
|
|
|
|
+ # Design документ для страниц (page)
|
|
|
|
|
+ pages:
|
|
|
|
|
+ version: "1.1"
|
|
|
views:
|
|
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()
|
|
|
|
|
|
|
+ # Все опубликованные страницы
|
|
|
|
|
+ published:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'page' and doc.status is 'published'
|
|
|
|
|
+ emit(doc.order || 0, doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Страницы по домену и языку
|
|
|
|
|
+ by_domain_language:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'page' and doc.status is 'published' and doc.domain and doc.language
|
|
|
|
|
+ for domain in doc.domain
|
|
|
|
|
+ for lang in doc.language
|
|
|
|
|
+ emit([domain, lang, doc.order || 0], doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Страницы по пути (для меню и навигации)
|
|
|
|
|
+ by_path:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'page' and doc.status is 'published' and doc.category_path
|
|
|
|
|
+ for path_segment in doc.category_path
|
|
|
|
|
+ emit([path_segment, doc.order || 0], doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Страницы по родительскому ID (для иерархии)
|
|
|
|
|
+ by_parent:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'page' and doc.status is 'published'
|
|
|
|
|
+ parent_id = doc.parent_id || 'root'
|
|
|
|
|
+ emit([parent_id, doc.order || 0], doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Защищенные страницы (требующие авторизации)
|
|
|
|
|
+ protected:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'page' and doc.status is 'published' and doc.protected
|
|
|
|
|
+ emit(doc.order || 0, doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Страницы для карты сайта
|
|
|
|
|
+ sitemap:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'page' and doc.status is 'published' and doc.show_in_sitemap != false
|
|
|
|
|
+ emit(doc.order || 0, doc)).toString()
|
|
|
|
|
|
|
|
- # Design документ для событий (events) с мультиязычными данными
|
|
|
|
|
- events_multilingual:
|
|
|
|
|
- version: "6.0"
|
|
|
|
|
|
|
+ # Design документ для событий (events)
|
|
|
|
|
+ events:
|
|
|
|
|
+ version: "1.2"
|
|
|
views:
|
|
views:
|
|
|
- # События по дате с мультиязычной информацией
|
|
|
|
|
- by_date_multilingual:
|
|
|
|
|
|
|
+ # Все опубликованные события
|
|
|
|
|
+ published:
|
|
|
map: ((doc) ->
|
|
map: ((doc) ->
|
|
|
if doc.type is 'event' and doc.status is 'published'
|
|
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()
|
|
|
|
|
-
|
|
|
|
|
|
|
+ emit(doc.event_data?.event_date || doc.created_at, doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # События по домену и языку
|
|
|
|
|
+ by_domain_language:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'event' and doc.status is 'published' and doc.domain and doc.language
|
|
|
|
|
+ for domain in doc.domain
|
|
|
|
|
+ for lang in doc.language
|
|
|
|
|
+ emit([domain, lang, doc.event_data?.event_date || doc.created_at], doc)).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()
|
|
|
|
|
-
|
|
|
|
|
|
|
+ upcoming:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'event' and doc.status is 'published' and doc.event_data
|
|
|
|
|
+ event_date = doc.event_data.event_date
|
|
|
|
|
+ if event_date and new Date(event_date) > new Date()
|
|
|
|
|
+ emit(event_date, doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Прошедшие события
|
|
|
|
|
+ past:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'event' and doc.status is 'published' and doc.event_data
|
|
|
|
|
+ event_date = doc.event_data.event_date
|
|
|
|
|
+ if event_date and new Date(event_date) <= new Date()
|
|
|
|
|
+ emit(event_date, doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # События по статусу
|
|
|
|
|
+ by_status:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'event' and doc.status is 'published' and doc.event_data
|
|
|
|
|
+ status = doc.event_data.status || 'upcoming'
|
|
|
|
|
+ emit([status, doc.event_data?.event_date || doc.created_at], doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Избранные события
|
|
|
|
|
+ featured:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'event' and doc.status is 'published' and doc.featured
|
|
|
|
|
+ emit(doc.event_data?.event_date || doc.created_at, doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # События по категории
|
|
|
|
|
+ by_category:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'event' and doc.status is 'published' and doc.category_id
|
|
|
|
|
+ emit([doc.category_id, doc.event_data?.event_date || doc.created_at], doc)).toString()
|
|
|
|
|
+
|
|
|
# События по местоположению
|
|
# События по местоположению
|
|
|
- by_location_multilingual:
|
|
|
|
|
|
|
+ by_location:
|
|
|
map: ((doc) ->
|
|
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()
|
|
|
|
|
|
|
+ if doc.type is 'event' and doc.status is 'published' and doc.event_data?.location
|
|
|
|
|
+ for location_array, lang_index in doc.event_data.location
|
|
|
|
|
+ for location in location_array
|
|
|
|
|
+ emit([location, doc.event_data?.event_date || doc.created_at], doc)).toString()
|
|
|
|
|
|
|
|
- # Design документ для товаров (products) с мультиязычными данными
|
|
|
|
|
- products_multilingual:
|
|
|
|
|
- version: "6.0"
|
|
|
|
|
|
|
+ # Design документ для товаров (products)
|
|
|
|
|
+ products:
|
|
|
|
|
+ version: "1.1"
|
|
|
views:
|
|
views:
|
|
|
- # Товары по статусу и доступности
|
|
|
|
|
- by_status_multilingual:
|
|
|
|
|
|
|
+ # Все опубликованные товары
|
|
|
|
|
+ published:
|
|
|
map: ((doc) ->
|
|
map: ((doc) ->
|
|
|
if doc.type is 'product' and doc.status is 'published'
|
|
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()
|
|
|
|
|
-
|
|
|
|
|
|
|
+ emit(doc.created_at, doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Товары по домену и языку
|
|
|
|
|
+ by_domain_language:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'product' and doc.status is 'published' and doc.domain and doc.language
|
|
|
|
|
+ for domain in doc.domain
|
|
|
|
|
+ for lang in doc.language
|
|
|
|
|
+ emit([domain, lang, doc.created_at], doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Товары по статусу наличия
|
|
|
|
|
+ by_availability:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'product' and doc.status is 'published' and doc.product_data
|
|
|
|
|
+ status = doc.product_data.status || 'available'
|
|
|
|
|
+ emit([status, doc.created_at], doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Избранные товары
|
|
|
|
|
+ featured:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'product' and doc.status is 'published' and doc.featured
|
|
|
|
|
+ emit(doc.created_at, doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Товары по категории
|
|
|
|
|
+ by_category:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'product' and doc.status is 'published' and doc.category_id
|
|
|
|
|
+ emit([doc.category_id, doc.created_at], doc)).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:
|
|
|
|
|
|
|
+ by_price:
|
|
|
map: ((doc) ->
|
|
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()
|
|
|
|
|
|
|
+ if doc.type is 'product' and doc.status is 'published' and doc.product_data?.price
|
|
|
|
|
+ price = doc.product_data.price[0] || 0
|
|
|
|
|
+ emit(price, doc)).toString()
|
|
|
|
|
|
|
|
- # Design документ для слайдеров (slides) с мультиязычными данными
|
|
|
|
|
- slides_multilingual:
|
|
|
|
|
- version: "6.0"
|
|
|
|
|
|
|
+ # Design документ для слайдеров (slides)
|
|
|
|
|
+ slides:
|
|
|
|
|
+ version: "1.1"
|
|
|
views:
|
|
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()
|
|
|
|
|
|
|
+ # Все активные слайды
|
|
|
|
|
+ active:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'slide' and doc.status is 'published' and doc.slide_data?.active != false
|
|
|
|
|
+ current_date = new Date().toISOString()
|
|
|
|
|
+ start_date = doc.slide_data.start_date || '2000-01-01'
|
|
|
|
|
+ end_date = doc.slide_data.end_date || '2100-01-01'
|
|
|
|
|
+ if start_date <= current_date <= end_date
|
|
|
|
|
+ emit(doc.slide_data?.order || 0, doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Слайды по домену и языку
|
|
|
|
|
+ by_domain_language:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'slide' and doc.status is 'published' and doc.slide_data?.active != false and doc.domain and doc.language
|
|
|
|
|
+ current_date = new Date().toISOString()
|
|
|
|
|
+ start_date = doc.slide_data.start_date || '2000-01-01'
|
|
|
|
|
+ end_date = doc.slide_data.end_date || '2100-01-01'
|
|
|
|
|
+ if start_date <= current_date <= end_date
|
|
|
|
|
+ for domain in doc.domain
|
|
|
|
|
+ for lang in doc.language
|
|
|
|
|
+ emit([domain, lang, doc.slide_data?.order || 0], doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Слайды по порядку отображения
|
|
|
|
|
+ by_order:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'slide' and doc.status is 'published' and doc.slide_data?.active != false
|
|
|
|
|
+ current_date = new Date().toISOString()
|
|
|
|
|
+ start_date = doc.slide_data.start_date || '2000-01-01'
|
|
|
|
|
+ end_date = doc.slide_data.end_date || '2100-01-01'
|
|
|
|
|
+ if start_date <= current_date <= end_date
|
|
|
|
|
+ emit(doc.slide_data.order || 0, doc)).toString()
|
|
|
|
|
|
|
|
- # Design документ для иерархических категорий с мультиязычностью
|
|
|
|
|
- categories_hierarchical_multilingual:
|
|
|
|
|
- version: "6.0"
|
|
|
|
|
|
|
+ # Design документ для категорий
|
|
|
|
|
+ categories:
|
|
|
|
|
+ version: "1.1"
|
|
|
views:
|
|
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()
|
|
|
|
|
|
|
+ # Все активные категории
|
|
|
|
|
+ active:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'category' and doc.active != false
|
|
|
|
|
+ emit(doc.level || 0, doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Категории по домену и языку
|
|
|
|
|
+ by_domain_language:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'category' and doc.active != false and doc.domain and doc.language
|
|
|
|
|
+ for domain in doc.domain
|
|
|
|
|
+ for lang in doc.language
|
|
|
|
|
+ emit([domain, lang, doc.level || 0], doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Категории по родительскому ID
|
|
|
|
|
+ by_parent:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'category' and doc.active != false
|
|
|
|
|
+ parent_id = doc.parent_id || 'root'
|
|
|
|
|
+ emit([parent_id, doc.order || 0], doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Категории для меню
|
|
|
|
|
+ menu:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'category' and doc.active != false and doc.show_in_menu != false
|
|
|
|
|
+ emit([doc.level || 0, doc.menu_order || 0], doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Избранные категории
|
|
|
|
|
+ featured:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'category' and doc.active != false and doc.featured
|
|
|
|
|
+ emit(doc.level || 0, doc)).toString()
|
|
|
|
|
|
|
|
- # Design документ для статистики и аналитики мультиязычного контента
|
|
|
|
|
- multilingual_statistics:
|
|
|
|
|
- version: "6.0"
|
|
|
|
|
|
|
+ # Design документ для настроек доменов
|
|
|
|
|
+ domain_settings:
|
|
|
|
|
+ version: "1.1"
|
|
|
views:
|
|
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()
|
|
|
|
|
|
|
+ # Все активные настройки доменов
|
|
|
|
|
+ active:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'domain_settings' and doc.active != false
|
|
|
|
|
+ emit(doc.domain, doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Настройки по приоритету
|
|
|
|
|
+ by_priority:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'domain_settings' and doc.active != false
|
|
|
|
|
+ emit(doc.priority || 0, doc)).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 документ для пользователей
|
|
|
|
|
+ users:
|
|
|
|
|
+ version: "1.1"
|
|
|
|
|
+ views:
|
|
|
|
|
+ # Все активные пользователи
|
|
|
|
|
+ active:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'user' and doc.active != false
|
|
|
|
|
+ emit(doc.email, doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Пользователи по роли
|
|
|
|
|
+ by_role:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'user' and doc.active != false
|
|
|
|
|
+ emit(doc.role, doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Пользователи по домену доступа
|
|
|
|
|
+ by_domain_access:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'user' and doc.active != false and doc.domains_access
|
|
|
|
|
+ for domain in doc.domains_access
|
|
|
|
|
+ emit([domain, doc.email], doc)).toString()
|
|
|
|
|
|
|
|
- # Design документ для работы с заказами
|
|
|
|
|
- orders_management:
|
|
|
|
|
- version: "6.0"
|
|
|
|
|
|
|
+ # Design документ для заказов
|
|
|
|
|
+ orders:
|
|
|
|
|
+ version: "1.1"
|
|
|
views:
|
|
views:
|
|
|
- # Заказы по статусу и домену
|
|
|
|
|
- by_status_and_domain:
|
|
|
|
|
|
|
+ # Все заказы
|
|
|
|
|
+ all:
|
|
|
map: ((doc) ->
|
|
map: ((doc) ->
|
|
|
if doc.type is 'order'
|
|
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()
|
|
|
|
|
|
|
+ emit(doc.created_at, doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Заказы по статусу
|
|
|
|
|
+ by_status:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'order'
|
|
|
|
|
+ emit([doc.status, doc.created_at], doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Заказы по пользователю
|
|
|
|
|
+ by_user:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'order' and doc.user_id
|
|
|
|
|
+ emit([doc.user_id, doc.created_at], doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Заказы по домену
|
|
|
|
|
+ by_domain:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'order' and doc.domain
|
|
|
|
|
+ emit([doc.domain, doc.created_at], doc)).toString()
|
|
|
|
|
|
|
|
- # Design документ для пользователей и управления доступом
|
|
|
|
|
- users_management:
|
|
|
|
|
- version: "6.0"
|
|
|
|
|
|
|
+ # Design документ для аудита
|
|
|
|
|
+ audit_logs:
|
|
|
|
|
+ version: "1.1"
|
|
|
views:
|
|
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()
|
|
|
|
|
|
|
+ # Все записи аудита
|
|
|
|
|
+ all:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'audit_log'
|
|
|
|
|
+ emit(doc.created_at, doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Записи аудита по пользователю
|
|
|
|
|
+ by_user:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'audit_log' and doc.user_id
|
|
|
|
|
+ emit([doc.user_id, doc.created_at], doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Записи аудита по типу ресурса
|
|
|
|
|
+ by_resource_type:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'audit_log' and doc.resource_type
|
|
|
|
|
+ emit([doc.resource_type, doc.created_at], doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Записи аудита по действию
|
|
|
|
|
+ by_action:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type is 'audit_log' and doc.action
|
|
|
|
|
+ emit([doc.action, doc.created_at], doc)).toString()
|
|
|
|
|
|
|
|
- # Design документ для системы уведомлений с мультиязычностью
|
|
|
|
|
- multilingual_notifications:
|
|
|
|
|
- version: "6.0"
|
|
|
|
|
|
|
+ # Универсальные представления для всех типов документов
|
|
|
|
|
+ universal:
|
|
|
|
|
+ version: "1.2"
|
|
|
views:
|
|
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()
|
|
|
|
|
|
|
+ # Документы по типу и домену
|
|
|
|
|
+ by_type_domain:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type and doc.domain
|
|
|
|
|
+ if Array.isArray(doc.domain)
|
|
|
|
|
+ for domain in doc.domain
|
|
|
|
|
+ emit([doc.type, domain, doc.created_at], doc)
|
|
|
|
|
+ else
|
|
|
|
|
+ emit([doc.type, doc.domain, doc.created_at], doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Документы по типу и статусу
|
|
|
|
|
+ by_type_status:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.type and doc.status
|
|
|
|
|
+ emit([doc.type, doc.status, doc.created_at], doc)).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Поиск по текстовым полям (для полнотекстового поиска)
|
|
|
|
|
+ text_search:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.title and Array.isArray(doc.title)
|
|
|
|
|
+ for title in doc.title
|
|
|
|
|
+ words = title.toLowerCase().split(/\s+/)
|
|
|
|
|
+ for word in words when word.length > 2
|
|
|
|
|
+ emit(word, {_id: doc._id, type: doc.type, title: doc.title})
|
|
|
|
|
+
|
|
|
|
|
+ if doc.content and Array.isArray(doc.content)
|
|
|
|
|
+ for content in doc.content
|
|
|
|
|
+ words = content.toLowerCase().split(/\s+/)
|
|
|
|
|
+ for word in words when word.length > 2
|
|
|
|
|
+ emit(word, {_id: doc._id, type: doc.type, content: content})
|
|
|
|
|
+
|
|
|
|
|
+ if doc.tags and Array.isArray(doc.tags)
|
|
|
|
|
+ for tag_array in doc.tags
|
|
|
|
|
+ for tag in tag_array
|
|
|
|
|
+ emit(tag.toLowerCase(), {_id: doc._id, type: doc.type, tags: doc.tags})).toString()
|
|
|
|
|
+
|
|
|
|
|
+ # Документы с поддержкой мультиязычности
|
|
|
|
|
+ multilingual:
|
|
|
|
|
+ map: ((doc) ->
|
|
|
|
|
+ if doc.language and Array.isArray(doc.language) and doc.domain
|
|
|
|
|
+ domain_array = if Array.isArray(doc.domain) then doc.domain else [doc.domain]
|
|
|
|
|
+ for domain in domain_array
|
|
|
|
|
+ for lang in doc.language
|
|
|
|
|
+ emit([domain, lang, doc.type, doc.created_at], doc)).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()
|
|
|
|
|
|
|
+# Экспорт design документов
|
|
|
|
|
+module.exports = design_documents
|