热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

MongoDB入门学习(三):MongoDB的增删查改

对于我们这种菜鸟来说,最重要的不是数据库的管理,也不是数据库的性能,更不是数据库的扩展,而是怎么用好这款数据库,也就是一个数据库提供的最核心的功能,增删查改。因为Mon

        对于我们这种菜鸟来说,最重要的不是数据库的管理,也不是数据库的性能,更不是数据库的扩展,而是怎么用好这款数据库,也就是一个数据库提供的最核心的功能,增删查改。

        因为MongoDB存储数据都是以文档的模式,所以在操作它的数据时,也是以文档为单位的。那么我们实现增删查改也是以文档为基础,不知道文档是什么的同学可以看看上篇介绍的基本概念。

1.插入文档

        向MongoDB集合中插入文档的基本方法是insert:

单个插入
> document = {key : value}
> db.collectionName.insert(document)
批量插入
> documents = [{key : value}, {key : value}, {key : value}, ...]
传入数组
> db.collectionName.insert(documents)
for循环
> for(var i = 0; i ... db.people.insert(documents[i]);
... }

        因为集合是无模式的,集合中的文档可以是各式各样的,所以在插入方面是很随意的,想一次插入很多数据的话可以使用for循环,也可以使用批量插入,传入一个由文档构成的数组。因为使用for循环来实现批量插入会为每次插入建立一个TCP连接,而传入数组实现批量插入只有一次TCP连接,所以在效率上来说,for的效率会比传入数组要低。

        还有一种插入的方式save,在shell中可以使用db.collectionName.function不加括号来看方法的实现,可以看出insert和save的区别,看个小例子:

> db.people.find()
{ "_id" : 1, "name" : "mary", "age" : 20 }
> db.people.insert({"_id" : 1, "name" : "amy", "age" : 22})
E11000 duplicate key error index: test.people.$_id_ dup key: { : 1.0 }
> db.people.save({"_id" : 1, "name" : "amy", "age" : 22})
> db.people.find()
{ "_id" : 1, "name" : "amy", "age" : 22 }

        本来people集合中已经有一个文档了,如果我们要插入的文档中的主键"_id"在集合中已经存在一样的值则会报错,而save就不会。没有一样的主键时,insert和save一样都执行插入操作,有一样的主键时,insert就报错,save就执行更新操作,用新文档的内容来替换已经原来的内容,和update操作一样,所以mary被替换成了amy。

        执行插入操作的时候,驱动程序先将数据转换成BSON的形式,然后再送入数据库,只检验是否包含了"_id"键,文档是否超过4MB(能插入的文档最大为4MB,超过了就不能存入数据库),而不进行别的验证和执行别的代码,所以远离了注入式攻击,使数据库更安全。

2.删除文档

        删除文档的基本方法是remove:

db.collectionName.remove()
db.collectionName.remove({})
db.collectionName.remove(condition)
db.collectionName.drop()

        前三种都是删除集合中的文档,第一个和第二个是一样的,都不指定删除的条件,这样会删除掉集合中所有的文档,第四个是删除该集合,连索引都删除了,如果要清除整个集合,直接删除集合的效率比删除集合中的所有文档更快。第三个指定了一个条件,比如删除people集合中name为mary的所有文档:

db.people.remove({"name" : "mary"})

3.更新文档

        更新文档的基本方法是update,虽然上面讲到了save在"_id"一样的时候也有这种功效,当然我们一般是不会以"_id"为更新条件的:

db.collectionName.uodate(condition, modifier, upsert, multi)

        update有四个参数,condition是查询文档,用来查询出要修改的文档,modifier是修改器文档,描述对查找到的文档做哪些修改,upsert表示如果没有该文档就插入这个心文档,默认为false,multi表示是否更新查询到的所有文档,默认为false,所以只更新查询到的第一个文档。但是我们平时经常用到的还是前两个参数,如果有必要就用后两个参数。因为更新操作是原子的,所以当有很多更新同时发生时,最后一次的更新操作才是最后的结果。下面我们将name为mary的文档age改为20:

> db.people.find()
{ "_id" : ObjectId("53a3a0b7abda49d7dfce102c"), "name" : "mary", "age" : 30, "country" : "US" }
> db.people.update({"name" : "mary"}, {"age" : 20})
> db.people.find()
{ "_id" : ObjectId("53a3a0b7abda49d7dfce102c"), "age" : 20 }

        但是最后的结果却出乎我们的预料,name字段和country字段都没有了,这样的update是用后面的文档替换查询到的文档,所以结果是正确的,只是我们的操作错误了。那我们每次更新不都要将原来的数据再写一次么,这样比写SQL更复杂啊,不过还有一种改进方式,在shell中将查询到的文档赋值给一个变量,然后再修改,最后在将这个变量替换原来的查询结果:

方式一:
> db.people.find()
{ "_id" : ObjectId("53a3a1c1abda49d7dfce102d"), "name" : "mary", "age" : 30, "country" : "US" }
> db.people.update({"name" : "mary"}, {"name" : "mary", "age" : 20})
> db.people.find()
{ "_id" : ObjectId("53a3a1c1abda49d7dfce102d"), "name" : "mary", "age" : 20 }
方式二:
> db.people.find()
{ "_id" : ObjectId("53a3a1c1abda49d7dfce102d"), "name" : "mary", "age" : 30, "country" : "US" }
> person = db.people.findOne()
{ "_id" : ObjectId("53a3a1c1abda49d7dfce102d"), "name" : "mary", "age" : 30, "country" : "US"}
> person.age = 20
> delete person.country
true
> db.people.update({"name" : "mary"}, person)
> db.people.find()
{ "_id" : ObjectId("53a3a1c1abda49d7dfce102d"), "name" : "mary", "age" : 20 }

        查询出name为mary的文档赋值给person,然后将person的age赋为20,删除country字段,再替换原来查询到的文档,如果一个文档有很多字段,而我们只要修改其中一到两个字段,这种方式就比第一种方式要简单的很多。但是这样就有个问题,如果findOne匹配到第二个mary,更新的时候却更新到了第一个mary,那就会出现"_id"重复的问题。这样就有了修改器的使用,是更新变的更简单高效。

        1).$set

           $set用来修改指定键的值(也可以是内嵌文档的键),如果这个键不存在就创建它,如:

> db.people.find()
{ "_id" : ObjectId("53a3b0e633c516902a43a790"), "name" : "mary", "age" : 30, "country" : "US", "school" : { "name" : "BeijingUniversity", "city" : "Beijing" } }
> db.people.update({"name" : "mary"}, {"$set" : {"age" : 20, "school.name" : "QinghuaUniversity"}})
> db.people.find()
{ "_id" : ObjectId("53a3b0e633c516902a43a790"), "name" : "mary", "age" : 20, "country" : "US", "school" : { "name" : "QinghuaUniversity", "city" : "Beijing" } }

        2).$unset

           $unset用来将键完全删除,如:

> db.people.find()
{ "_id" : ObjectId("53a3a1c1abda49d7dfce102d"), "name" : "mary", "age" : 20, "country" : "US" }
> db.people.update({"name" : "mary"}, {"$unset" : {"country" : 1}})
> db.people.find()
{ "_id" : ObjectId("53a3a1c1abda49d7dfce102d"), "age" : 20, "name" : "mary" }

        3).$inc

           $inc用来增加已有键的值,当键不存在时创建这个键,再在初始值0的基础上再增加,$inc对应的键必须是数字类型的,如果是别的数据类型就会报错,如:

> db.people.find()
{ "_id" : ObjectId("53a3b0e633c516902a43a790"), "age" : 20, "country" : "US", "name" : "mary" }
> db.people.update({"name" : "mary"}, {"$inc" : {"age" : 1}})
> db.people.find()
{ "_id" : ObjectId("53a3b0e633c516902a43a790"), "age" : 21, "country" : "US", "name" : "mary" }
> db.people.update({"name" : "mary"}, {"$inc" : {"age" : -2}})
> db.people.find()
{ "_id" : ObjectId("53a3b0e633c516902a43a790"), "age" : 19, "country" : "US", "name" : "mary" }
> db.people.update({"name" : "mary"}, {"$inc" : {"country" : 2}})
Cannot apply $inc modifier to non-number

        4).$push,$pushAll

           $push用来对内置数组的操作,给内置数组添加元素,$push是添加一个元素,$pushAll是添加一个数组,如:

> db.people.find()
{ "_id" : ObjectId("53a3b47733c516902a43a791"), "name" : "mary", "friends" : [ "amy", "join" ] }
> db.people.update({"name" : "mary"}, {"$push" : {"friends" : "joe"}})
> db.people.find()
{ "_id" : ObjectId("53a3b47733c516902a43a791"), "friends" : [ "amy", "join", "joe" ], "name" : "mary" }
> db.people.update({"name" : "mary"}, {"$push" : {"friends" : ["jodan", "mical"]}})
> db.people.find()
{ "_id" : ObjectId("53a3b47733c516902a43a791"), "friends" : [ "amy", "join", "joe", [ "jodan", "mical" ] ], "name" : "mary" }

        5).$addToSet,$each

           $addToSet用来给内置数组添加元素,如果数组中已经存在相同值的元素,就不添加,用来避免重复,通常和$each组合使用,$each后面跟一个数组用来添加该数组中的元素如:

> db.people.find()
{ "_id" : ObjectId("53a3c18533c516902a43a794"), "friends" : [ "amy" ], "name" : "mary" }
> db.people.update({"name" : "mary"}, {"$addToSet" : {"friends" : "join"}})
> db.people.find()
{ "_id" : ObjectId("53a3c18533c516902a43a794"), "friends" : [ "amy", "join" ], "name" : "mary" }
> db.people.update({"name" : "mary"}, {"$addToSet" : {"friends" : {"$each" : ["amy", "join", "jodan"]}}})
> db.people.find()
{ "_id" : ObjectId("53a3c18533c516902a43a794"), "friends" : [ "amy", "join", "jodan" ], "name" : "mary" }

        6).$pull,$pullAll

           $pull用来删除内置数组中的某元素,$pullAll删除某几个元素,如:

 db.people.find()
{ "_id" : ObjectId("53a3c18533c516902a43a794"), "name" : "mary", "friends" : [ "amy", "join", "jodan", "mical" ] }
> db.people.update({"name" : "mary"}, {"$pull" : {"friends" : "amy"}})
> db.people.find()
{ "_id" : ObjectId("53a3c18533c516902a43a794"), "friends" : [ "join", "jodan", "mical" ], "name" : "mary" }
> db.people.update({"name" : "mary"}, {"$pullAll" : {"friends" : ["join", "jodan"]}})
> db.people.find()
{ "_id" : ObjectId("53a3c18533c516902a43a794"), "friends" : [ "mical" ], "name" : "mary" }

        7).$pop

           $pop也是用来删除内置数组中的一个元素,这个元素要么是数组的第一个元素要么是数组的最后一个元素,如:

> db.people.find()
{ "_id" : ObjectId("53a3c18533c516902a43a794"), "friends" : [ "mical", "amy", "join" ], "name" : "mary" }
> db.people.update({"name" : "mary"}, {"$pop" : {"friends" : 1}})
> db.people.find()
{ "_id" : ObjectId("53a3c18533c516902a43a794"), "friends" : [ "mical", "amy" ], "name" : "mary" }
> db.people.update({"name" : "mary"}, {"$pop" : {"friends" : -1}})
> db.people.find()
{ "_id" : ObjectId("53a3c18533c516902a43a794"), "friends" : [ "amy" ], "name" : "mary" }

        8).$

           $用来定位内置数组的元素,MongoDB的内置数组下标也是从0开始递增的,所以我们可以通过对数组进行定位修改,如:

> db.people.find()
{ "_id" : ObjectId("53a3c18533c516902a43a794"), "friends" : [ "amy", "join", "jodan" ], "name" : "mary" }
> db.people.update({"name" : "mary"}, {"$set" : {"friends.0" : "mical"}})
> db.people.find()
{ "_id" : ObjectId("53a3c18533c516902a43a794"), "friends" : [ "mical", "join", "jodan" ], "name" : "mary" }
> db.people.update({"name" : "mary", "friends" : "join"}, {"$set" : {"friends.$" : "amy"}})
> db.people.find()
{ "_id" : ObjectId("53a3c18533c516902a43a794"), "friends" : [ "mical", "amy", "jodan" ], "name" : "mary" }

            上面第一种更新,我们就是单纯的想把mary的第一个朋友变成mical。第二种更新,我们不知道mary的朋友join是在数组的哪个位置,但是确实有这么个朋友,就查询到了通过$进行定位,然后再将其变成amy。

        9).$rename

           $rename用来对字段重命名,如:

> db.people.find()
{ "_id" : ObjectId("53a3c80a33c516902a43a795"), "name" : "mary", "friends" : [ "mical", "amy", "jodan" ] }
> db.people.update({"name" : "mary"}, {"$rename" : {"friends" : "classmates"}})
> db.people.find()
{ "_id" : ObjectId("53a3c80a33c516902a43a795"), "classmates" : [ "mical", "amy", "jodan" ], "name" : "mary" }

        文档的插入,删除和更新都是瞬间完成的,因为客户端并不需要等待数据库的响应,这个也不是异步操作,因为客户端将文档给数据库了其他的操作都由数据库本身来操作,和客户端就完全没关系了。文档的查询就不一样了,客户端必须要等到数据库返回来的查询结果。

4.查询文档

        查询文档的基本方法是find:

db.collectionName.find(condition, returnKey)
db.collectionName.find()
db.collectionName.find({})
db.collectionName.find({}, {"name" : 1})
db.collectionName.find({}, {"name" : 0})

        find有两个参数,condition为查询文档,returnKey为指定返回的字段。不指定查询条件或者查询条件是一个空文档,那就是查询集合中的所有文档,返回值指定键,如果为1就是返回该键的值,如果为0就返回除了该键以外的所有键的值。

        当然我们除了精确查询,比如查询name为mary,age为20的文档并返回其friends字段的结果,还会有更复杂的模糊查询条件,比如范围查询,age在20到30之间的文档等。这时候在查询文档中就要添加这些查询条件。

        1).$lt,$lte,$gt,$gte,$ne

           $lt,$lte,$gt,$gte分别对应<,<=,>,>=,可以组合起使用来查询一个范围,$ne表示不等于,如:

> db.people.find()
{ "_id" : ObjectId("53a3e01d33c516902a43a797"), "name" : "mary", "age" : 20 }
{ "_id" : ObjectId("53a3e02533c516902a43a798"), "name" : "amy", "age" : 23 }
{ "_id" : ObjectId("53a3e02d33c516902a43a799"), "name" : "join", "age" : 18 }
{ "_id" : ObjectId("53a3e03c33c516902a43a79a"), "name" : "jodan", "age" : 25 }
{ "_id" : ObjectId("53a3e04933c516902a43a79b"), "name" : "mical", "age" : 19 }
> db.people.find({"age" : {"$gte" : 19, "$lte" : 23}, "name" : {"$ne" : "mary"}}, {"_id" : 0})
{ "name" : "amy", "age" : 23 }
{ "name" : "mical", "age" : 19 }

        2).$or,$in,$nin

           $or,$in表示几个条件中满足一个就可以返回,但是$in只能用于在同一个字段中给几个条件,而or可以用于不同字段,还能和$in搭配使用,$nin和$in相反,表示只要不符合几个给定的条件就可以返回,如:

> db.people.find()
{ "_id" : ObjectId("53a3e01d33c516902a43a797"), "name" : "mary", "age" : 20 }
{ "_id" : ObjectId("53a3e02533c516902a43a798"), "name" : "amy", "age" : 23 }
{ "_id" : ObjectId("53a3e02d33c516902a43a799"), "name" : "join", "age" : 18 }
{ "_id" : ObjectId("53a3e03c33c516902a43a79a"), "name" : "jodan", "age" : 25 }
{ "_id" : ObjectId("53a3e04933c516902a43a79b"), "name" : "mical", "age" : 19 }
> db.people.find({"age" : {"$in" : [19, 20, 21, 22, 23]}}, {"_id" : 0})
{ "name" : "mary", "age" : 20 }
{ "name" : "amy", "age" : 23 }
{ "name" : "mical", "age" : 19 }
> db.people.find({"age" : {"$nin" : [19, 20, 21, 22, 23]}}, {"_id" : 0})
{ "name" : "join", "age" : 18 }
{ "name" : "jodan", "age" : 25 }
> db.people.find({"$or" : [{"age" : {"$in" : [19, 20, 21, 22, 23]}}, {"name" : "jodan"}]}, {"_id" : 0})
{ "name" : "mary", "age" : 20 }
{ "name" : "amy", "age" : 23 }
{ "name" : "jodan", "age" : 25 }
{ "name" : "mical", "age" : 19 }

        3).$not,$mod

           $not是元条件句,可以用在任何其他条件上,表示非,$mod表示取模运算,对应运算符%,如:

> db.people.find()
{ "_id" : ObjectId("53a3e01d33c516902a43a797"), "name" : "mary", "age" : 20 }
{ "_id" : ObjectId("53a3e02533c516902a43a798"), "name" : "amy", "age" : 23 }
{ "_id" : ObjectId("53a3e02d33c516902a43a799"), "name" : "join", "age" : 18 }
{ "_id" : ObjectId("53a3e03c33c516902a43a79a"), "name" : "jodan", "age" : 25 }
{ "_id" : ObjectId("53a3e04933c516902a43a79b"), "name" : "mical", "age" : 19 }
> db.people.find({"age" : {"$not" : {"$mod" : [5, 0]}}}, {"_id" : 0})
{ "name" : "amy", "age" : 23 }
{ "name" : "join", "age" : 18 }
{ "name" : "mical", "age" : 19 }

           这里表示对age进行取模运算,如果里面的$mod条件为对5取模,为0就符合条件,加上外面的$not,表示非,也就是模不为0就符合条件。

        4).$exists,null

           $exists表示判断键值是否已经存在,它的值为true或者false,null表示空值或不存在的字段,如:

> db.variable.find()
{ "_id" : ObjectId("53a3e91f33c516902a43a79c"), "x" : 1, "y" : null }
{ "_id" : ObjectId("53a3e92733c516902a43a79d"), "x" : 3 }
{ "_id" : ObjectId("53a3e92e33c516902a43a79e"), "x" : 5, "y" : 10 }
> db.variable.find({"y" : null}, {"_id" : 0})
{ "x" : 1, "y" : null }
{ "x" : 3 }
> db.variable.find({"y" : {"$in" : [null], "$exists" : true}}, {"_id" : 0})
{ "x" : 1, "y" : null }

           当我们只查询y为null时,由于第二个文档中没有y字段所以也符合条件,那么如果要查询的文档y必须要存在而且为null,就用到了$exists。

        5).正则表达式

           没错,MongoDB也支持正则表达式来查询字符串,这就使得对字符串的查询更加的简单高效,正则表达式是查询字符串的神器,如:

> db.people.find()
{ "_id" : ObjectId("53a3e01d33c516902a43a797"), "name" : "mary", "age" : 20 }
{ "_id" : ObjectId("53a3e02533c516902a43a798"), "name" : "amy", "age" : 23 }
{ "_id" : ObjectId("53a3e02d33c516902a43a799"), "name" : "join", "age" : 18 }
{ "_id" : ObjectId("53a3e03c33c516902a43a79a"), "name" : "jodan", "age" : 25 }
{ "_id" : ObjectId("53a3e04933c516902a43a79b"), "name" : "mical", "age" : 19 }
> db.people.find({"name" : /jo.*/}, {"_id" : 0})
{ "name" : "join", "age" : 18 }
{ "name" : "jodan", "age" : 25 }

        6).对内置数组的查询,$all,$size,$slice

           对内置数组最简单的查询就是精确的指定条件,指定的条件表示该内置数组包含该元素,而不是等于,这是很有意思的,精确查询一般的字段都是指该字段的值等于我们给定的值,而对内置数组而言,是表示包含该元素。

           如果要对数组通过多元素来匹配就要用到$all,如果包含$all给定的数组中的元素,就符合条件判断,$size表示数组的大小,$slice是find中第二个参数中指定的内容,表示返回数组的一个子集合,也就是查询到的数组返回哪几个元素,正数表示前几个,负数表示后几个,如:

> db.food.find()
{ "_id" : ObjectId("53a3ebcf33c516902a43a79f"), "fruit" : [ "apple", "banana", "orange" ] }
{ "_id" : ObjectId("53a3ee0e33c516902a43a7a0"), "fruit" : [ "bnana" ] }
{ "_id" : ObjectId("53a3ee1933c516902a43a7a1"), "fruit" : [ "apple", "orange" ] }
> db.food.find({"fruit" : "apple"}, {"_id" : 0})
{ "fruit" : [ "apple", "banana", "orange" ] }
{ "fruit" : [ "apple", "orange" ] }
> db.food.find({"fruit" : {"$all" : ["apple", "orange"]}}, {"_id" : 0})
{ "fruit" : [ "apple", "banana", "orange" ] }
{ "fruit" : [ "apple", "orange" ] }
> db.food.find({"fruit" : {"$size" : 2}}, {"_id" : 0})
{ "fruit" : [ "apple", "orange" ] }
> db.food.find({"fruit" : {"$size" : 3}}, {"_id" : 0, "fruit" : {"$slice" : -2}})
{ "fruit" : [ "banana", "orange" ] }
> db.food.find({"fruit" : {"$size" : 3}}, {"_id" : 0, "fruit" : {"$slice" : 2}})
{ "fruit" : [ "apple", "banana" ] }

        7).对内置数组中文档的查询,$elemMatch

           对内置数组中文档的查询其实就是将内置数组中的元素替换成文档形式,$elemMatch保证我们的查询是在内置数组中同一文档中进行的,如:

> db.grade.find()
{
"_id" : ObjectId("53a3f4d933c516902a43a7a4"),
"name" : "jim",
"age" : 20,
"score" : [
{
"course" : "computer",
"credit" : 2,
"teacher" : "mary"
},
{
"course" : "english",
"credit" : 1,
"teacher" : "join"
}
]
}
{
"_id" : ObjectId("53a3fbf7901e10bdd70adf9e"),
"name" : "amy",
"age" : 21,
"score" : [
{
"course" : "computer",
"credit" : 2,
"teacher" : "nola"
},
{
"course" : "chinese",
"credit" : 3,
"teacher" : "mary"
}
]
}
方式一、这里指定score中course为computer和teacher为mary是查不到的
> db.grade.find({"score" : {"course" : "computer", "teacher" : "mary"}})
方式二、指定score中元素的全部字段就能查到了,而且顺序不能变
> db.grade.find({"score" : {"course" : "computer", "teacher" : "mary", "credit" : 2}})
> db.grade.find({"score" : {"course" : "computer", "credit" : 2, "teacher" : "mary"}})
{
"_id" : ObjectId("53a3f4d933c516902a43a7a4"),
"name" : "jim",
"age" : 20,
"score" : [
{
"course" : "computer",
"credit" : 2,
"teacher" : "mary"
},
{
"course" : "english",
"credit" : 1,
"teacher" : "join"
}
]
}
方式三、指定score.course为computer和score.teacher为mary居然把两个都查出来了
> db.grade.find({"score.course" : "computer", "score.teacher" : "mary"})
{
"_id" : ObjectId("53a3f4d933c516902a43a7a4"),
"name" : "jim",
"age" : 20,
"score" : [
{
"course" : "computer",
"credit" : 2,
"teacher" : "mary"
},
{
"course" : "english",
"credit" : 1,
"teacher" : "join"
}
]
}
{
"_id" : ObjectId("53a3fbf7901e10bdd70adf9e"),
"name" : "amy",
"age" : 21,
"score" : [
{
"course" : "computer",
"credit" : 2,
"teacher" : "nola"
},
{
"course" : "chinese",
"credit" : 3,
"teacher" : "mary"
}
]
}
方式四、通过$elemMatch来查询,得到我们想要的结果
> db.grade.find({"score" : {"$elemMatch" : {"course" : "computer", "teacher" : "mary"}}})
{
"_id" : ObjectId("53a3f4d933c516902a43a7a4"),
"name" : "jim",
"age" : 20,
"score" : [
{
"course" : "computer",
"credit" : 2,
"teacher" : "mary"
},
{
"course" : "english",
"credit" : 1,
"teacher" : "join"
}
]
}

           对于方式一和方式二可能有个难理解的地方,为什么只指定其中部分字段就查询不到,而必须要指定全部的字段才可以呢,查询内置数组的时候只要指定fruit为apple就能查询出包含apple的数组,这里为什么要指定全部的字段呢。其实这是一个误区,在这里一个内置文档才相当于fruit中的一种水果,也就是数组中的一个元素,如果连这个元素都缺斤少两,在数组中如何查询的到呢。

           对于方式三,指定score.course和score.teacher为啥把两个都查询出来了,明明第二个结果不是我们想要的,course为computer时teacher并不为mary,但是course为chinese时teacher为mary,所以第二个结果中的确存在score.course为computer,并且同时存在score.teacher为mary,那这是将两个文档的字段组合起来达到我们的要求了。显然这并不是我们想要的,所以就必须使用$elemMatc,也就是方式四,它保证了我们查询是在数组中同一个文档元素中进行的。

        7).$where

           $where可以执行任何的Javascript作为查询的一部分,所以$where几乎可以做所有的事,但是这种方式必须要将每个文档从BSON转换成Javascript对象,然后再通过$where的表达式来执行,而且还不能用索引。因此用$where是下下策,在你实在走投无路的时候再用。用法也比较简单,就是对this的操作,如果某文档满足我们自定义的条件就返回true,那么该文档就会被返回,如:

> db.fruit.find()
{ "_id" : ObjectId("53a412c7901e10bdd70adfa2"), "apple" : 2, "banana" : 6, "orange" : 3 }
{ "_id" : ObjectId("53a412d1901e10bdd70adfa3"), "apple" : 5, "banana" : 7, "orange" : 8 }
db.fruit.find({"$where" : function(){
for(var x in this){
for(var y in this){
if(this[x] / this[y] == 2){
return true;
}
}
}
}})
{ "_id" : ObjectId("53a412c7901e10bdd70adfa2"), "apple" : 2, "banana" : 6, "orange" : 3 }

        数据库使用游标来返回find的执行结果,客户端对游标的实现通常能够对查询到的结果进行有效的控制,可以限制结果的数量,略过部分结果,根据任意方向,任意键的组合对结果进行排序,或者执行其他一些功能强大的操作。

        在shell中使用游标,要先将查询到的结果赋值给一个变量,然后通过游标一次查看一条结果。如果查询结果没有赋值给变量,那么shell会自动迭代,打印所有查询到的结果。游标提供了两个方法,hasNext返回是否还有结果,next返回下一个结果用来遍历查询到的结果,还提供了limit,skip,sort几个方法来操作结果。因为游标对象的方法都返回游标本身,所以这几个方法可以以任意的顺序进行组合。如:

> db.people.find()
{ "_id" : ObjectId("53a3e01d33c516902a43a797"), "name" : "mary", "age" : 20 }
{ "_id" : ObjectId("53a3e02533c516902a43a798"), "name" : "amy", "age" : 23 }
{ "_id" : ObjectId("53a3e02d33c516902a43a799"), "name" : "join", "age" : 18 }
{ "_id" : ObjectId("53a3e03c33c516902a43a79a"), "name" : "jodan", "age" : 25 }
{ "_id" : ObjectId("53a3e04933c516902a43a79b"), "name" : "mical", "age" : 19 }
> var cursor = db.people.find();
> while(cursor.hasNext()){ obj = cursor.next(); print(obj.name); }
mary
amy
join
jodan
mical
> var cursor = db.people.find().limit(3);
> while(cursor.hasNext()){ obj = cursor.next(); print(obj.name); }
mary
amy
join
> var cursor = db.people.find().skip(2);
> while(cursor.hasNext()){ obj = cursor.next(); print(obj.name); }
join
jodan
mical
> var cursor = db.people.find().sort({"name" : 1});
> while(cursor.hasNext()){ obj = cursor.next(); print(obj.name); }
amy
jodan
join
mary
mical
> var cursor = db.people.find().skip(2).limit(2).sort({"name" : 1});
> while(cursor.hasNext()){ obj = cursor.next(); print(obj.name); }
join
mary

        limit表示对查询到的结果加上数量上限,如果查询到的结果数量多于这个上限,则返回这个数量的结果,如果不够,就返回全部的结果。skip表示略过一定数量的结果,如果查询到的结果数量少于这个数量,就没有任何文档返回,如果多于,则略过这个数量的文档后再返回。sort表示对查询结果进行排序,指定字段并指定顺序,1为升序,-1为降序,也可以同时对多个字段进行排序。


推荐阅读
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Excel数据处理中的七个查询匹配函数详解
    本文介绍了Excel数据处理中的七个查询匹配函数,以vlookup函数为例进行了详细讲解。通过示例和语法解释,说明了vlookup函数的用法和参数的含义,帮助读者更好地理解和运用查询匹配函数进行数据处理。 ... [详细]
  • Oracle分析函数first_value()和last_value()的用法及原理
    本文介绍了Oracle分析函数first_value()和last_value()的用法和原理,以及在查询销售记录日期和部门中的应用。通过示例和解释,详细说明了first_value()和last_value()的功能和不同之处。同时,对于last_value()的结果出现不一样的情况进行了解释,并提供了理解last_value()默认统计范围的方法。该文对于使用Oracle分析函数的开发人员和数据库管理员具有参考价值。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • 本文介绍了在处理不规则数据时如何使用Python自动提取文本中的时间日期,包括使用dateutil.parser模块统一日期字符串格式和使用datefinder模块提取日期。同时,还介绍了一段使用正则表达式的代码,可以支持中文日期和一些特殊的时间识别,例如'2012年12月12日'、'3小时前'、'在2012/12/13哈哈'等。 ... [详细]
  • Python爬虫中使用正则表达式的方法和注意事项
    本文介绍了在Python爬虫中使用正则表达式的方法和注意事项。首先解释了爬虫的四个主要步骤,并强调了正则表达式在数据处理中的重要性。然后详细介绍了正则表达式的概念和用法,包括检索、替换和过滤文本的功能。同时提到了re模块是Python内置的用于处理正则表达式的模块,并给出了使用正则表达式时需要注意的特殊字符转义和原始字符串的用法。通过本文的学习,读者可以掌握在Python爬虫中使用正则表达式的技巧和方法。 ... [详细]
  • 如何实现织梦DedeCms全站伪静态
    本文介绍了如何通过修改织梦DedeCms源代码来实现全站伪静态,以提高管理和SEO效果。全站伪静态可以避免重复URL的问题,同时通过使用mod_rewrite伪静态模块和.htaccess正则表达式,可以更好地适应搜索引擎的需求。文章还提到了一些相关的技术和工具,如Ubuntu、qt编程、tomcat端口、爬虫、php request根目录等。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • PHP图片截取方法及应用实例
    本文介绍了使用PHP动态切割JPEG图片的方法,并提供了应用实例,包括截取视频图、提取文章内容中的图片地址、裁切图片等问题。详细介绍了相关的PHP函数和参数的使用,以及图片切割的具体步骤。同时,还提供了一些注意事项和优化建议。通过本文的学习,读者可以掌握PHP图片截取的技巧,实现自己的需求。 ... [详细]
  • Android JSON基础,音视频开发进阶指南目录
    Array里面的对象数据是有序的,json字符串最外层是方括号的,方括号:[]解析jsonArray代码try{json字符串最外层是 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 本文介绍了Linux Shell中括号和整数扩展的使用方法,包括命令组、命令替换、初始化数组以及算术表达式和逻辑判断的相关内容。括号中的命令将会在新开的子shell中顺序执行,括号中的变量不能被脚本余下的部分使用。命令替换可以用于将命令的标准输出作为另一个命令的输入。括号中的运算符和表达式符合C语言运算规则,可以用在整数扩展中进行算术计算和逻辑判断。 ... [详细]
  • 如何在php中将mysql查询结果赋值给变量
    本文介绍了在php中将mysql查询结果赋值给变量的方法,包括从mysql表中查询count(学号)并赋值给一个变量,以及如何将sql中查询单条结果赋值给php页面的一个变量。同时还讨论了php调用mysql查询结果到变量的方法,并提供了示例代码。 ... [详细]
author-avatar
福田商务汽车-日照方傲
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有