Я использую библиотеку Mongo php в службе, которая отвечает за хранение и извлечение некоторых социальных данных, в частности, из Facebook, и просто фрагмент, это выглядит примерно так: коллекция сообщений сообщений:
{
"_id":"5865aa8e9bbbe400010f97a2",
"insights":[
{
"name":"post_story_adds_unique",
"period":"lifetime",
"values":[
{
"value":10
}
]
},
{
"name":"post_story_adds",
"period":"lifetime",
"values":[
{
"value":11
}
]
},
{
"name":"post_story_adds_by_action_type_unique",
"period":"lifetime",
"values":[
{
"value":{
"like":10,
"comment":1
}
}
]
},
{
"name":"post_story_adds_by_action_type",
"period":"lifetime",
"values":[
{
"value":{
"like":10,
"comment":1
}
}
]
},
{
"name":"post_impressions_unique",
"period":"lifetime",
"values":[
{
"value":756
}
]
}
]
},
{
"_id":"586d939b9bbbe400010f9f12",
"insights":[
{
"name":"post_story_adds_unique",
"period":"lifetime",
"values":[
{
"value":76
}
]
},
{
"name":"post_story_adds",
"period":"lifetime",
"values":[
{
"value":85
}
]
},
{
"name":"post_story_adds_by_action_type_unique",
"period":"lifetime",
"values":[
{
"value":{
"like":73,
"comment":8,
"share":2
}
}
]
},
{
"name":"post_story_adds_by_action_type",
"period":"lifetime",
"values":[
{
"value":{
"like":74,
"comment":9,
"share":2
}
}
]
},
{
"name":"post_impressions_unique",
"period":"lifetime",
"values":[
{
"value":9162
}
]
}
]
}
Мы можем отметить, что все под-документы постов, то есть метрики, присутствуют в каждом посте, несомненно, с их соответствующими значениями.
Я считаю, что представленная выше структура данных не оптимальна для работы; если столкнуться с ситуацией, спроецировать пару значений этих поддокументов, скажем, post_story_adds_by_action_type
и post_impressions_unique
«s value
свойство, нам нужно выполнить условие для всех поддокументов, чтобы соответствовать name
собственность на post_story_adds_by_action_type
или же post_impressions_unique
,
Я старался $elemMatch(projection)
, но, как говорится в документации, он возвращает только первый соответствующий элемент массива. Я смог сделать так:
$this->db->$collection->find([],
[
'projection' => [
'insights' => [
'$elemMatch' => [
'name' => 'post_impressions_unique'
]
],
'_id' => 0,
'insights.values.value' => 1,
],
]);
MongoDB\Driver\Cursor
объект возвращается только с желаемым значением, установив это 'insights.values.value' => 1
из поддокументов, которые имеют name
равно post_impressions_unique
,
Первое, о чем я подумал, это, конечно, использовать $or
логический оператор:
$this->db->$collection->find([],
[
'projection' => [
'insights' => [
'$elemMatch' => [
'$or' => [
[
'name' => [
'$eq' => 'post_story_adds_by_action_type',
]
],
[
'name' => [
'$eq' => 'post_impressions_unique',
]
]
]
]
]
],
'_id' => 0,
'insights.name' => 1,
'insights.values.value.like' => 1,
'insights.values.value' => 1,
]);
Обратите внимание на прогнозы
'insights.values.value.share' => 1
'insights.values.value' => 1
в соответствии с позицией значения различных поддокументов.
Конечно, это не сработало, я получил массив post_impressions_unique
только субдокументы; поэтому я должен был попробовать структуру агрегации https://docs.mongodb.com/manual/reference/operator/aggregation/filter/ :
$this->db->$name->aggregate(
[
[
'$project' => [
'insights' => [
'$filter' => [
'input' => '$insights',
'as' => 'name',
'cond' => [
'$or' => [
[
'$eq' => [
'name', '$post_story_adds_by_action_type',
]
],
[
'$eq' => [
'name', '$post_impressions_unique',
]
],
],
],
],
],
'_id' => 0,
'values.value.like' => 1,
'values.value' => 1,
],
]
]);
Это тоже не сработало, в этом случае я получил массив пустых insights
объекты.
Я подумал об использовании Laravel-MongoDB пакет и воспользоваться преимуществами Eloquent строитель.
DB::collection($collection)->project(['insights' => ['$elemMatch' => ['name' => 'post_story_adds_unique']]])->get();
или же
DB::collection($collection)->project(['insights' => [
'$filter' => [
'input' => '$insights',
'as' => 'name',
'cond' => [
'name' => 'post_story_adds_unique',
]
]
],
'values.value.like' => 1
])->get();
Но все же я не мог получить значение в поддокументе. Я проверил Builder::project()
функции, и кажется, что он также использует структуру агрегации, но я не смог выяснить соответствующий синтаксис для этого, если таковые имеются.
Мои вопросы следующие:
1- Как я могу получить определенные поддокументы? insights.values.value
а также name
свойства, где name
Матчи post_impressions_unique
? И наоборот, как получить поддокументы insignts.values.value.share
а также name
свойства, когда последний совпадает post_story_adds_by_action_type
?
2- Какой правильный синтаксис использовать $filter
в пределах $project(aggregation)
?
Это в основном большая часть исследований, которые я проводил, и мне кажется, что я бегаю кругами.
Ценю твою помощь.
Спасибо.
Вы можете попробовать что-то вроде этого.
использование $$
запись для доступа к переменной, определенной в итерации в $filter
а также $map
,
$map
используется для обрезки ответа на дисплей values
а также name
от insights
массив.
[
[
'$project' => [
'insights' => [
'$map' => [
'input' => [
'$filter' => [
'input' => '$insights',
'as' => 'insightf',
'cond' => [
'$or' => [
[
'$eq' => [
'$$insightf.name', 'post_story_adds_by_action_type',
]
],
[
'$eq' => [
'$$insightf.name', 'post_impressions_unique',
]
],
],
],
],
],
'as' => 'insightm',
'in' => [
'values' => '$$insightm.values.value',
'name' => '$$insightm.name',
],
],
],
'_id' => 0
],
]
];
Других решений пока нет …