我正在尝试使用MongoDB统计单词使用情况。我的收藏目前看起来像这样:
{'_id':###, 'username':'Foo', words:[{'word':'foo', 'count':1}, {'word':'bar', 'count':1}]}
当发布一个新帖子时,我将所有新单词提取到一个数组中,但我试图想要插入单词数组并在该单词已经存在的情况下递增计数。
在上面的示例中,例如,如果用户“Foo”发布了“lorem ipsum foo”,我会将“lorem”和“ipsum”添加到用户单词数组中,但会增加“foo”的计数。 / p>
这可以在一个查询中使用吗?目前我正在使用addToSet:
'$addToSet':{'words':{'$each':word_array}}
但这似乎没有提供任何增加字数的方法。
非常感谢一些帮助:)
答案 0 :(得分:9)
如果您愿意从列表切换到哈希(对象),则可以原子地执行此操作。
从docs:“$inc
...增量字段中的数字值if字段存在于对象中,否则将字段设置为数字值。”
{ $inc : { field : value } }
所以,如果你能重构你的容器和对象:
words: [
{
'word': 'foo',
'count': 1
},
...
]
为:
words: {
'foo': 1,
'other_word: 2,
...
}
您可以将操作update
用于:
{ $inc: { 'words.foo': 1 } }
如果'foo'不存在,将创建{ 'foo': 1 }
,否则增加foo。
E.g:
$ db.bar.insert({ id: 1, words: {} });
$ db.bar.find({ id: 1 })
[
{ ..., "words" : { }, "id" : 1 }
]
$ db.bar.update({ id: 1 }, { $inc: { 'words.foo': 1 } });
$ db.bar.find({ id: 1 })
[
{ ..., "id" : 1, "words" : { "foo" : 1 } }
]
$ db.bar.update({ id: 1 }, { $inc: { 'words.foo': 1 } });
$ db.bar.find({ id: 1 })
[
{ ..., "id" : 1, "words" : { "foo" : 2 } }
]
答案 1 :(得分:2)
不幸的是,在使用您的架构的单个更新中无法执行此操作。您的架构有点可疑,应该转换为具有字计数器的专用集合,例如:
db.users {_id:###, username:'Foo'}
db.words.counters {_id:###, word:'Word', userId: ###, count: 1}
这将避免很多问题,例如:
这两种方案都需要两次更新来执行您想要的操作,这会引入原子性问题。通过循环遍历word_array来更新每个单词更好,更安全(并且可以使用两种解决方案)。