记录简单的mongo中数组的增删改查

最近在用golang写一个简单的存储聊天记录的功能,库使用的是mgo。用 mongo 作为数据库的时候遇到一个问题:在用户发信息时需要将两个人分别加入到各自的聊天列表中,我的期望是一个人只需对应一个文档,其中有个数组用来存储聊天列表信息,所以我要的效果就是对mongo数组的增删改查。

增加

在实际的编写代码中,在增加操作需要加入判断,因为对于聊天列表不存在的情况需要创建:

//查询此人是否存在于自己的聊天列表
err = DB.C(CHAT_LIST).Find(bson.M{`userid`: params.From}).One(&ChatList{})
if err != nil && err != mgo.ErrNotFound {
  log.Println(`查询聊天列表失败:` + err.Error())
  return err
}
//创建列表
if err == mgo.ErrNotFound {
  err = DB.C(CHAT_LIST).Insert(ChatList{
    UserId:       params.From,
    ChatListItem: []ChatListItem{tc},
  })
  if err != nil {
    log.Println(`创建聊天列表失败:` + err.Error())
    return err
  }
}

在已存在的情况下,我的需求是更新数组元素,用$push即可:

//查询此人是否存在于chatlist中
err = DB.C(CHAT_LIST).Find(bson.M{
  `userid`:              params.From,
  `chatlistitem.userid`: params.To,
}).One(&ChatList{})
if err != nil && err != mgo.ErrNotFound {
  log.Println(`查询聊天列表失败:` + err.Error())
  return err
}
//不存在,加入列表
if err == mgo.ErrNotFound {
  _, err = DB.C(CHAT_LIST).Upsert(bson.M{
    `userid`: params.From,
  }, bson.M{
    "$push": bson.M{"chatlistitem": tc},
  })
  if err != nil {
    log.Println(`加入聊天列表失败:` + err.Error())
    return err
  }
}

如果数据有不允许重复的需求,可以换成$addToSet这个操作,数据不存在的话则会成功插入,如果存在的话则不会插入

我的数据结构是这样的:

这里我对于已存在的情况需要更新其他字段,所以没用这个。

查找

这里查询时可以直接根据集合的子对象chatlistitem.userid查找

err = DB.C(CHAT_LIST).Find(bson.M{
		`userid`:              params.From,
		`chatlistitem.userid`: params.To,
	}).One(&ChatList{})
	if err != nil {
		//不存在的情况,加入列表
		if err == mgo.ErrNotFound {
			err = DB.C(CHAT_LIST).Insert(ChatList{
				UserId:       params.From,
				ChatListItem: []ChatListItem{tc},
			})
			return err
		}
		return err
	}

对于已存在的情况,需要更新列表的未读消息数unreadcount,由于这个涉及到另一个集合,这里我用了管道处理,

叫管道是因为它可以将每一次的操作传递到下一级,用$match根据条件查询,然后用$group$sum直接得到总数量

type ResultCount struct {
	Count int
}
var tr []ResultCount

err = DB.C(CHAT).Pipe([]bson.M{
  {`$match`: bson.M{`msgid`: params.MsgId, `from`: params.To, `status`: 0}},
  {`$group`: bson.M{"_id": nil, `count`: bson.M{`$sum`: 1}}},
}).All(&fr)

修改

修改就相对简单了,根据条件修改相应的数据,其中的.$是定位符,用在不清楚具体是哪条数据,指代符合条件的那一条

	_, err = DB.C(CHAT_LIST).Update(bson.M{
		`userid`:              params.To,
		`chatlistitem.userid`: params.From,
	}, bson.M{
		"$set": bson.M{"chatlistitem.$": fc},
	})

删除

删除时首先根据条件找到对应的对象,然后使用pull操作,后面对应要删除的条件

	err := DB.C(CHAT_LIST).Update(bson.M{
		`userid`:              from,
		`chatlistitem.userid`: to,
	}, bson.M{
		"$pull": bson.M{"chatlistitem": bson.M{"userid": to}},
	})