我们知道,MongoDB属于文档型数据库,其存储的文档类型都是JSON对象。正是由于这一特性,我们在Node.js中会经常使用MongoDB进行数据的存取。但由于Node.js是异步执行的,这就导致我们无法保证每一次的数据库save操作都是原子型的。也就是说,如果客户端连续两次发起同一事件将数据存入数据库,很可能会导致数据被重复保存。高并发的情况下,哪怕是你在代码中已经做了非常严格的校验,例如插入数据前判断要保存的数据是否已经存在,但仍然有可能会出现数据被重复保存的风险。因为在异步执行中,你没有办法保证哪个线程先执行,哪个线程后执行,客户端发起的所有请求并非按我们想象的都是顺序执行的。一个较好的解决办法是在Mongo数据库的所有表中创建唯一索引。事实上,MongoDB默认会为所有表创建一个_id字段的唯一索引(可以取消)。如果你想在Node.js中通过mongoose.schema来自动创建索引,可以参考下面的代码:

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var customerSchema = new mongoose.Schema({
cname: String,
cellPhone, String,
sender: String,
tag: String,
behaviour: Number,
createTime: {
type: Date,
default: Date.now
},
current:{
type: Boolean,
default: true
}
}, {
versionKey: false
});
customerSchema.index({cname:1,cellPhone:1,sender:1,tag:1,behaviour:1}, {unique: true});

module.exports = mongoose.model('customer', customerSchema);

  上面的model中我们定义了表customer的结构,并通过index()方法在字段cname,cellPhone,sender,tag,behaviour上创建了唯一索引,这样当包含这些字段的重复数据被插入时,数据库会抛出异常。借用mongoose,如果数据库表之前已经被创建并且程序正在运行中,当我们修改model并添加索引,然后重新启动app,只要有对该model的访问,mongoose会自动进行检测并创建索引。当然,如果数据出现重复,则索引创建会失败。此时我们可以通过在创建索引时添加dropDups选项,让数据库自动将重复的数据删除,如:

customerSchema.index({cname:1,cellPhone:1,sender:1,tag:1,behaviour:1}, {unique: true, dropDups: true});

  不过据MongoDB的官方说明,自3.0以后的版本不再使用该选项,而且也并没有提供替代的解决办法。貌似官方不再提供创建索引时自动删除重复记录的功能。那如何才能快速有效地找出重复的记录并且删除呢?首先我们要找出这些记录,然后通过remove()方法进行删除。下面的查询语句可以找出给定字段有重复数据的记录:

db.collection.aggregate([
{ $group: {
_id: { firstField: "$firstField", secondField: "$secondField" },
uniqueIds: { $addToSet: "$_id" },
count: { $sum: 1 }
}},
{ $match: {
count: { $gt: 1 }
}}
])

  替换_id属性的值以指定你想要进行判断的字段。相应地,在Node.js中代码如下:

var deferred = Q.defer();
var group = { firstField: "$firstField", secondField: "$secondField"};
model.aggregate().group({
_id: group,
uniqueIds: {$addToSet: '$_id'},
count: {$sum: 1}
}).match({ count: {$gt: 1}}).exec(deferred.makeNodeResolver());
return deferred.promise;

  上述代码使用了Q来替换函数执行中的回调。在Node.js的异步编程中,使用Q来处理回调是个不错的选择。

  下面是返回的结果:

/* 1 */
{
"result" : [
{
"_id" : {
"cellPhone" : "15827571111",
"actId" : ObjectId("5694565fa50fea7705f01789")
},
"uniqueIds" : [
ObjectId("569b5d03b3d206f709f97685"),
ObjectId("569b5d01b3d206f709f97684")
],
"count" : 2.0000000000000000
},
{
"_id" : {
"cellPhone" : "18171282222",
"actId" : ObjectId("566b0d8dc02f61ae18e68e48")
},
"uniqueIds" : [
ObjectId("566d16e6cf86d12d1abcee8b"),
ObjectId("566d16e6cf86d12d1abcee8a")
],
"count" : 2.0000000000000000
}
],
"ok" : 1.0000000000000000
}

  从结果中可以看到,一共有两组数据相同的记录,所以返回的result数组的长度为2。uniqueIds属性为一个数组,其中存放了重复记录的_id字段的值,通过该值我们可以使用remove()方法来查找并删除对应的数据。

补充:Mongoose支持findOneAndUpdate(在MongoDB中对应的方法叫findAndModify),选项upsert=true表示当要要更新的数据不存在时会自动创建。该选项默认值为false。示例代码如下:

var query = {'username':req.user.username};
req.newData.username = req.user.username;
MyModel.findOneAndUpdate(query, req.newData, {upsert:true}, function(err, doc){
if (err) return res.send(500, { error: err });
return res.send("succesfully saved");
});

  通过该方法我们可以将数据的唯一性校验交给MongoDB来完成。

更多专业前端知识,请上 【猿2048】www.mk2048.com

使用aggregate在MongoDB中查找重复的数据记录相关推荐

  1. excel表格多列数据中查找重复行数据

    1.做透视表统计 2.设置显示格式 3.取消分类汇总 4.拷贝到原数据后面 5.排序

  2. oracle countif函数,字符串截取substr、excel表中查找重复数据countif

    1.字符串截取substr =left(a1,2)意思是取A1左面就是前面开始去2个字符 =right(a1,3)及时A1右面 就是走后面开始取3个字符 要是中间取 =mid(a1,2,4) 就是走A ...

  3. Sublime中查找重复行的正则表达式

    Sublime中查找重复行的正则表达式 先按F9对所有内容排序: 然后Ctrl+F 调出查找面板: 将下面的正则表达式放进去,并选择正则表达式选项 正则表达式:^(.+)$[\r\n](^\1$[\r ...

  4. Java实现 LeetCode 609 在系统中查找重复文件(阅读理解+暴力大法)

    609. 在系统中查找重复文件 给定一个目录信息列表,包括目录路径,以及该目录中的所有包含内容的文件,您需要找到文件系统中的所有重复文件组的路径.一组重复的文件至少包括二个具有完全相同内容的文件. 输 ...

  5. mysql 找表重复数据,mysql 数据表中查找重复记录

    mysql 数据表中查找重复记录 复制代码 代码如下: select user_name,count(*) as count from user_table group by user_name ha ...

  6. C#LINQ在列表中查找重复项

    本文翻译自:C# LINQ find duplicates in List 使用LINQ,如何从List<int>检索包含重复项不止一次及其值的列表? #1楼 参考:https://sta ...

  7. 在excel中如何筛选重复数据_Excel表格技巧—如何在 Excel 中查找重复值

    今天和大家一起分享一下excel表格中如何快速查找重复值,在办公中很经常需要它. 先打开一张需要查找重复数据或重复值的EXCLE表格,如图我们以B2做为查找列: 点击工具菜单栏的"开始&qu ...

  8. 如何获取mongodb中的最后N条记录?

    我找不到任何记录在案的文件. 默认情况下,find()操作将从头开始获取记录. 如何获取mongodb中的最后N条记录? 编辑:我也希望返回的结果从最近到最近排序,而不是相反. #1楼 您可以使用so ...

  9. 【SQL】查找重复的数据

    @[查找重复的数据语句) 场景 使用PLSQL,查找ORACLE中从表中重复的外键id.主从表分开,主:从->1:多 语句意义 select id from tablename group by ...

最新文章

  1. 介绍一个打怪升级练习 Python 的网站,寓教于乐~
  2. 网站页面设计基本尺寸
  3. 连表查询使用in_SQL 组合查询
  4. Failed to install UTRUST.apk on device 'ZTE_SP920': Too many open files
  5. 课堂练习:返回一个二维数组中最大子数组的和
  6. 定时执行java程序_如何让Java程序定时运行
  7. 小汤学编程之JAVA基础day10——常用类(二):String常用方法、正则、StringBuffer和StringBuilder、Math和Random类、日期类和数字类
  8. [wordpress]更新插件时,免去FTP操作
  9. 暴怒程序员的呐喊:别让我做那些没用的东西
  10. 【Golang】关于从切片中删除某个元素时会覆盖底层数组的说明
  11. python--os
  12. Endnote X8激活注册信息
  13. Python sklearn 实现过采样和欠采样
  14. LED点阵屏动画展示
  15. 4G 全网通DTU是什么 有哪些功能应用
  16. 【三次集训】Day1思维题题解报告
  17. PHP对接美团配送接口遇到的问题
  18. 联想小新潮7000-13安装黑苹果笔记,无需无线网卡(无需U盘+win双系统+opencore)
  19. Windows如何使文件显示扩展名
  20. aptio2018设置u盘启动_如何设置bios让电脑从u盘启动_进入bios设置U盘启动的步骤

热门文章

  1. Windows编程初步(三)【说明:有敏感字眼已全删,不知道为啥还审核不通过】
  2. Windows编程之互动与动画
  3. html属性和dom属性的区别,HTML属性与DOM属性的区别?
  4. matlab cat函数_如何用Matlab编写贪吃蛇游戏?(持续更新)
  5. java 定义变量时 赋值与不赋值_探究Java中基本类型和部分包装类在声明变量时不赋值的情况下java给他们的默认赋值...
  6. ASP.NET Core MVC 之依赖注入 View
  7. H3C 三种生成树协议特性的比较
  8. 使用Mongo索引需要注意的几个点
  9. 两种解决IE6不支持固定定位的方法
  10. 【Python】Python中对目录路径的要求