2017-01-24 2 views
0

У меня есть структура таблицы, как показано ниже.Как получить либо существующий документ, либо новый документ

{ 
"_id" : ObjectId("5870f1d9dd0ef6e62102e6b8"), 
"product" : "product1", 
"title" : "Alt Summit 1", 
"category" : "category1", 
"order" : 1 
} 
{ 
"_id" : ObjectId("5870f1d9dd0ef6e62102e6b9"), 
"product" : "product2", 
"title" : "Alt Summit 2", 
"category" : "category1", 
"order" : 2 
} 
    { 
"_id" : ObjectId("5870f1d9dd0ef6e62102e6ba"), 
"product" : "product1", 
"title" : "Alt Summit 1", 
"category" : "category1", 
"order" : 2, 
"added_by" : user1 
} 
{ 
"_id" : ObjectId("5870f1d9dd0ef6e62102e6bb"), 
"product" : "product2", 
"title" : "Alt Summit 2", 
"category" : "category1", 
"order" : 1, 
"added_by" : user1 
} 
{ 
"_id" : ObjectId("5870f1d9dd0ef6e62102e6bc"), 
"product" : "product3", 
"title" : "Alt Summit 3", 
"category" : "category1", 
"order" : 3, 
"added_by" : user1 
} 
{ 
"_id" : ObjectId("5870f1d9dd0ef6e62102e6bd"), 
"product" : "product4", 
"title" : "Alt Summit 4", 
"category" : "category1", 
"order" : 4 
} 

Я хотел бы сначала объяснить структуру базы данных.

У меня есть продукты по умолчанию для каждого пользователя на моем веб-сайте, и пользователи могут добавлять свои собственные продукты в список, или они могут переупорядочить существующий список. когда они добавят новый продукт, он будет добавлен их именем пользователя. когда они повторно заказывают продукты, я получаю существующие записи по умолчанию и вставляю, добавляя имя пользователя и изменяя порядок (вы поймете, что если вы заметите вышеприведенные данные).

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

Например, если мне нужно получить все продукты для пользователя1 в категории1, то вывод должен быть следующим (отсортировано в соответствии с полем заказа). Если вы внимательно наблюдаете за вышеуказанными данными, тот же продукт повторяется с дополнительным полем с именем added_by и измененным порядком. Я хочу получить заказ пользователя, если пользователь его настроит, если не по умолчанию.

{ 
"_id" : ObjectId("5870f1d9dd0ef6e62102e6bb"), 
"product" : "product2", 
"title" : "Alt Summit 2", 
"category" : "category1", 
"order" : 1, 
"added_by" : user1 
} 
{ 
"_id" : ObjectId("5870f1d9dd0ef6e62102e6ba"), 
"product" : "product1", 
"title" : "Alt Summit 1", 
"category" : "category1", 
"order" : 2, 
"added_by" : user1 
} 
{ 
"_id" : ObjectId("5870f1d9dd0ef6e62102e6bc"), 
"product" : "product3", 
"title" : "Alt Summit 3", 
"category" : "category1", 
"order" : 3, 
"added_by" : user1 
} 
{ 
"_id" : ObjectId("5870f1d9dd0ef6e62102e6bd"), 
"product" : "product4", 
"title" : "Alt Summit 4", 
"category" : "category1", 
"order" : 4 
} 

Я открыт для любого предложения, если я должен изменить структуру таблицы. Но в любой момент времени я мог бы получить выход, о котором я говорил выше.

+0

'db.yourCollection.find ({ "категории": "category1", "added_by": "user1"}). Рода ({ "порядок": 1})' должна возвращать курсор, что вы» искать, нет? – Adam

+0

No @Adam Я все равно должен получать продукты по умолчанию, если пользователь не перенаправил объекты. Вышеприведенный запрос даст мне только пользовательские продукты или пользовательские заказы. Если в той же категории есть один и тот же продукт, который по умолчанию добавлен пользователем, я должен получить заказ пользователя вместе с другими продуктами по умолчанию. – Shravya

+0

Продукты по умолчанию определяются как те, у которых нет ключа '' added_by''? Если да, попробуйте 'db.yourCollection.find ({" $ или ": [{" category ":" category1 "," added_by ":" user1 "}, {" added_by ": {" $ exists ": false} }]}).sort ({"order": 1}) ' – Adam

ответ

1

Вы можете попробовать следующую агрегацию с текущей версией Mongo 3.4.

$match документы для критериев запроса.

$group документы на product и выбрать $first на основе ранее порядок сортировки при сохранении документа с $$ROOT.

$replaceRoot для продвижения документа root на верхний уровень.

'$ sort' by order Поле.

db.collection.aggregate([{ 
    $match: { 
    "category": "category1", 
     $or: [{ 
      "added_by": "user1" 
     }, { 
      "added_by": { 
       "$exists": false 
      } 
     }] 
    } 
}, { 
    $group: { 
     "_id": "$product", 
     "root": { 
      "$first": "$$ROOT" 
     } 
    } 
}, { 
    $replaceRoot: { 
     newRoot: "$root" 
    } 
},{ 
    $sort: { 
     "order": 1 
    } 
}]) 

Update после комментария OP в

$group документы по product и $push все продукты с $$ROOT.

$project стадии для сравнения $size если не $eq до 1, то $filter, чтобы выбрать продукт с added_by поле.

db.collection.aggregate([{ 
    $match: { 
     "category": "category1", 
     $or: [{ 
      "added_by": "user1" 
     }, { 
      "added_by": { 
       "$exists": false 
      } 
     }] 
    } 
}, { 
    $group: { 
     "_id": "$product", 
     "products": { 
      "$push": "$$ROOT" 
     } 
    } 
}, { 
    $project: { 
     "_id": 0, 
     "product": { 
      "$arrayElemAt": [{ 
        "$cond": [ 
         { 
          $eq: [{$size: "$products"}, 1] 
         }, 
         "$products", 
         { 
          "$filter": { 
           input: "$products", 
           as: "product", 
           cond: { 
            $ifNull: ["$$product.added_by", false] 
           } 
          } 
         } 
        ] 
       }, 
       0 
      ] 
     } 
    } 
}, { 
    $replaceRoot: { 
     newRoot: "$product" 
    } 
}, { 
    $sort: { 
     "order": 1 
    } 
}]); 
+0

Спасибо за ответ @Veeram. Я вижу, что вы выбираете первый документ из двух. Но, есть ли способ, которым я выбираю документ, который имеет поле added_by вместо того, чтобы выбирать первый или последний элемент. Я думаю, что для структуры я разместил решение, которое вы дали, все еще работает хорошо. Я все равно проверю, но было бы здорово, если бы вы могли обновить изменения, упомянутые в этом комментарии. – Shravya

+0

Добро пожаловать. Я обновлю ответ, но мне просто нужно понять его немного больше. Думаю, я допустил ошибку и должен был выбрать последний продукт. Причиной выбора последнего было думать, что вы будете заказывать заказ продукта после заказа по умолчанию. Поэтому, сортируя по конвейеру, у меня будет последний продукт переупорядочения. Разве это не так? Может ли пользователь выбрать заказ? – Veeram

+0

В большинстве случаев да, мы должны выбрать последний продукт. Но я думаю, что у меня совсем другой сценарий, который вы не слышали раньше. Нет, какой порядок я хочу выбрать, если он добавлен пользователем внутри категории. Поскольку не только переупорядочение продуктов пользователь может также добавлять продукты в эту категорию, в этом случае существует вероятность того, что продукт по умолчанию будет когда-то впереди или ниже того же продукта, добавленного пользователем. Поэтому, чтобы сделать эту работу, я хочу, чтобы она не основывалась на первом или последнем, но я хочу, чтобы пользователь добавил продукт либо он может быть до или после продукта по умолчанию. – Shravya