RethinkDB - Как объединять и усреднять объекты
У меня есть документы, структурированные следующим образом:
[
{
'post': 1,
'tags': [1, 2],
'poll': {
'a': 2,
'b': 2
}
},
{
'post': 1,
'tags': [3],
'poll': {
'a': 4,
'b': 6
}
},
]
Как я могу объединить их так, чтобы tags
будет объединение всех тегов в этих сообщениях и poll
будет усреднено? Из приведенного выше примера результат должен выглядеть следующим образом:
[
{
'post': 1,
'tags': [1, 2, 3],
'poll': {
'a': 3,
'b': 4
}
}
]
Благодарю.
2 ответа
Решение
Я думаю, что мы можем использовать map-reduce
так как мы превращаем много документов в один. Нечто подобное должно работать:
r.expr([
{
'post': 1,
'tags': [1, 2],
'poll': {
'a': 2,
'b': 2
}
},
{
'post': 1,
'tags': [3],
'poll': {
'a': 4,
'b': 6,
}
},
])
.merge(function(doc) {
return {
'poll': doc('poll').coerceTo('array').map(function(poll) { return [poll(0), [poll(1)]] }).coerceTo('object')
}
})
.reduce(function(left, right) {
return {
'post': left('post'),
'tags': left('tags').setUnion(right('tags')),
'poll': left('poll').keys().setUnion(right('poll').keys()).map(function(k) {
return [k,
left('poll')(k).default([]).union(right('poll')(k).default([]))
]
})
}
})
.merge(function(doc) {
return {
poll: doc('poll').map(function(poll) {
return [poll(0), poll(1).avg()]
}).coerceTo('object')
}
})
Это производит:
{
"poll": {
"a": 3,
"b": 4
},
"post": 1,
"tags": [1, 2, 3]
}
Исправлена версия, изначально предложенная kureikain:
r.expr([
{
'post': 1,
'tags': [1, 2],
'poll': {
'a': 2,
'b': 2
}
},
{
'post': 1,
'tags': [3],
'poll': {
'a': 4,
'b': 6,
}
},
{
'post': 1,
'tags': [2],
'poll': {
'a': 1,
'b': 3,
}
},
])
.merge(function(doc) {
return {
'poll': doc('poll').coerceTo('array').map(function(poll) { return [poll(0), [poll(1)]] }).coerceTo('object')
}
})
.reduce(function(left, right) {
return {
'post': left('post'),
'tags': left('tags').setUnion(right('tags')),
'poll': left('poll').keys().map(function(k) {
return [k, left('poll')(k).default([]).union(right('poll')(k).default([]))]
}).coerceTo('object')
}
})
.merge(function(doc) {
return {
poll: doc('poll').keys().map(function(k) {
return [k, doc('poll')(k).avg()]
}).coerceTo('object')
}
})