mongodb 如果存在则递增,否则插入

mongodb increment if exists otherwise insert

在下面的代码中,如果 itemId 和时间戳不存在,我想插入一个值,否则如果它已经存在,我想增加它

Collection.update({
                itemId: itemId,
                timestamp: moment.unix(timestamp).set('seconds', 0).toDate(),
            },
            {
                '$inc': {
                    'data.ph1': data.ph1,
                    'data.ph2': data.ph2,
                    'data.ph3': data.ph3,
                    'data.total': data.total
                },
            },
            { upsert: true },
            (err,resp) => {
                if(err) {
                    reject(err);
                } else {  
                    resolve('minute value incremented' + gatewayId );
                }
            });

它最终创建了多个文档。提前谢谢你。

编辑:你实际上不需要唯一索引来让upserts工作,但是当你做很多upserts时仍然推荐它and/or collection 挺大的。

Edit:正如 Neil Yunn 所指出的,您已经将时间戳的 seconds-part 设置为零,但忘记对 milliseconds-part.

您应该为您的 upsert 提供一个唯一字段,以便 MongoDB 有机会找到可能存在的记录。您的字段 itemIdtimestamp 应在 collection.

中标记为唯一索引

在Mongoshell中输入

db.items.createIndex({"itemId": 1, "timestamp": 1}, {"unique": true})

items 替换为您 collection 的真实姓名。

您仍然有毫秒部分(或者至少它会以这种方式显示),因此只要该部分在当前分钟内是唯一的,这仍将插入一个新文档。

这是您的代码,它错误地保留了毫秒数:

var timestamp = ( Date.now() / 1000 );

console.log(new Date());
console.log(timestamp);
console.log(moment.unix(timestamp).set("seconds",0).toDate());
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/moment.min.js"></script>

当您也删除毫秒时,它是正确的:

var timestamp = ( Date.now() / 1000 );

console.log(new Date());
console.log(timestamp);
console.log(moment.unix(timestamp).set("seconds",0).set("milliseconds",0).toDate());
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/moment.min.js"></script>

或者在传入之前简单地四舍五入 timestamp 值:

var timestamp = ( Date.now() / 1000 )
console.log(new Date());
timestamp = timestamp - ( timestamp % 60 );
console.log(timestamp);
console.log(moment.unix(timestamp).toDate());
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/moment.min.js"></script>

因此,当日期实际四舍五入到您预期的 "minute" 时,就没问题了。

这里的底线是 "upsert" 仅在提供的条件(本质上是文档的 "key" )实际上不匹配任何现有文档时才会出现,因此有些东西明显不同每个请求和最有可能的候选人是您代码中的 timestamp 值及其后续转换。

也就是说,除非您实际上是从外部或已经定义的来源读取 timestamp,否则获得 "current time" 的最佳方法是简单地使用普通的 Date 方法:

var timestamp = Date.now();
timestamp = timestamp - ( timestamp % ( 1000 * 60 ) );
console.log(new Date(timestamp));

这应该可以完成这项工作,而无需弄乱其他导入的库。

所以你真的应该看看为什么你有你当前的代码,如果你正在读取一个已经定义的值那么实际上 "ensure" 毫秒和秒在四舍五入中被删除,就像模方法通常做的那样最好的。

除时间戳本身之外的唯一其他原因是每个请求中更改的实际 itemId 值。但是,如果您这样做,那么该操作是预期的,并且当然会创建一个新文档,其中 "combination" 不存在,因为这就是它的目的。