Datastore
get
根據@id返回一個實例,find()的簡潔使用,查找不到結果時,返回null
<span style="font-size:12px;">Hotel hotel = ds.get(Hotel.class, hotelId);</span>
Find
對Query的包裝,可以返回Query,也支持Iterable<T> and the QueryResults interface。
支持操作:["=", "==","!=", "<>", ">", "<", ">=", "<=", "in", "nin", "all", "size", "exists"]
span style="font-size:12px;">Datastore ds = ... //use in a loop for(Hotel hotel : ds.find(Hotel.class, "stars >", 3)) print(hotel); //get back as a list List<Hotel> hotels = ds.find(Hotel.class, "stars >", 3).asList(); //sort the results List<Hotel> hotels = ds.find(Hotel.class, "stars >", 3).sort("-stars").asList(); //get the first matching hotel, by querying with a limit(1) Hotel gsHotel = ds.find(Hotel.class, "name", "Grand Sierra").get(); //same as Hotel gsHotel = ds.find(Hotel.class, "name =", "Grand Sierra").get();</span>
Save
<span style="font-size:12px;">Hotel hotel = new Hotel(); ds.save(hotel); //@Id field is filled in for you (after the save), if you didn't set it. ObjectId id = hotel.getId();</span>
Delete
方法將刪除對象的基於查詢的id或Entity。
<span style="font-size:12px;">Datastore ds = ... ds.delete(Hotel.class, "Grand Sierra Resort"); //use a query ds.delete(ds.createQuery(Hotel.class).filter("pendingDelete", true));</span>
FindAndDelete
刪除一個對象,同時返回刪除的對象,該方法會查找到第一個對象並且刪除
<span style="font-size:12px;">Hotel grandSierra = ds.findAndDelete(ds.get(Hotel.class, "Grand Sierra Resort"));</span>
Update
更新用戶最后一次登錄時間
<span style="font-size:12px;">public void loggedIn() { long now = System.currentTimeMillis(); Query<User> me = datastore.createQuery(User.class).field(Mapper.ID_KEY).equal(id); UpdateOperations<User> ops = datastore.createUpdateOperations(User.class).set("lastLogin", now); ds.update(me , ops); lastLogin = now; }</span>
ensure index and caps
在注冊實例到morphia之后,每次啟動應用、管理實例或部署腳本的時候,創建index和包含的集合, 同步的
如果系統已經存在index和包含的集合,那將不做任何操作,如果當前設置不一樣,將報錯寫日志,但不對已存在的集合做任何操作
<span style="font-size:12px;">m.map(MyEntity.class); ds.ensureIndexes(); //creates all defined with @Indexed ds.ensureCaps(); //creates all collections for @Entity(cap=@CappedAt(...))</span>
Updating(On the server)
總之,當你通過Datesote調用update方法時就會向MongoDB服務器發送一個修改已存在數據的指令。
interface Datastore { ... /** updates all entities found with the operations*/ <T> UpdateResults<T> update(Query<T> query, UpdateOperations<T> ops); /** updates all entities found with the operations; if nothing is found insert the update as an entity if "createIfMissing" is true*/ <T> UpdateResults<T> update(Query<T> query, UpdateOperations<T> ops, boolean createIfMissing); /** updates the first entity found with the operations*/ <T> UpdateResults<T> updateFirst(Query<T> query, UpdateOperations<T> ops); /** updates the first entity found with the operations; if nothing is found insert the update as an entity if "createIfMissing" is true*/ <T> UpdateResults<T> updateFirst(Query<T> query, UpdateOperations<T> ops, boolean createIfMissing); /** updates the first entity found with the operations; if nothing is found insert the update as an entity if "createIfMissing" is true*/ <T> UpdateResults<T> updateFirst(Query<T> query, T entity, boolean createIfMissing); } public interface UpdateOperations<T> { /** sets the field value */ UpdateOperations<T> set(String fieldExpr, Object value); /** removes the field */ UpdateOperations<T> unset(String fieldExpr); /** adds the value to an array field*/ UpdateOperations<T> add(String fieldExpr, Object value); UpdateOperations<T> add(String fieldExpr, Object value, boolean addDups); /** adds the values to an array field*/ UpdateOperations<T> addAll(String fieldExpr, List<?> values, boolean addDups); /** removes the first value from the array*/ UpdateOperations<T> removeFirst(String fieldExpr); /** removes the last value from the array*/ UpdateOperations<T> removeLast(String fieldExpr); /** removes the value from the array field*/ UpdateOperations<T> removeAll(String fieldExpr, Object value); /** removes the values from the array field*/ UpdateOperations<T> removeAll(String fieldExpr, List<?> values); /** decrements the numeric field by 1*/ UpdateOperations<T> dec(String fieldExpr); /** increments the numeric field by 1*/ UpdateOperations<T> inc(String fieldExpr); /** increments the numeric field by value (negatives are allowed)*/ UpdateOperations<T> inc(String fieldExpr, Number value);
The Field Expression
屬性表達式是用在所有的操作上的,可以是單個的屬性名,也可以是用點“.”連接的嵌套屬性。在表達式中你也可以使用位置操作副($)。在屬性
表達式中沒有標准,你可以使用任何在MongoDB服務端有效符號。
事例初始化
一下所有的實例創建的連接和Morphia實例都使用的一下代碼。
Morphia morphia = new Morphia(); morphia.map(Hotel.class).map(Address.class); Datastore datastore = morphia.createDatastore("MorphiaSampleDb"); Hotel hotel = new Hotel("Fairmont", 3, new Address("1 Rideau Street", "Ottawa", "K1N8S7", "Canada")); datastore.save(hotel); UpdateOperations<Hotel> ops; // This query will be used in the samples to restrict the update operations to only the hotel we just created. // If this was not supplied, by default the update() operates on all documents in the collection. // We could use any field here but _id will be unique and mongodb by default puts an index on the _id field so this should be fast! Query<Hotel> updateQuery = datastore.createQuery(Hotel.class).field("_id").equal(hotel.getId()); // The Mapper class also provides a public static of the default _id field name for us... Query<Hotel> updateQuery = datastore.createQuery(Hotel.class).field(Mapper.ID_KEY).equal(hotel.getId());
注意: 使用的是 equal() 而不是 equals()。
@Entity("hotels") public class Hotel { @Id private ObjectId id; private String name; private int stars; @Embedded private Address address; @Embedded List<Integer> roomNumbers = new ArrayList<Integer>(); // ... getters and setters } @Embedded public class Address { private String street; private String city; private String postalCode; private String country; // ... getters and setters }
set/unset
// 改變Hotel的name屬性值 ops = datastore.createUpdateOperations(Hotel.class).set("name", "Fairmont Chateau Laurier"); datastore.update(updateQuery, ops); //也可以操作嵌套文檔, 改變address的city屬性值 ops = datastore.createUpdateOperations(Hotel.class).set("address.city", "Ottawa"); datastore.update(updateQuery, ops); // 刪除Hotel的name屬性值 // 當下會訪問Hotel時name屬性為null ops = datastore.createUpdateOperations(Hotel.class).unset("name"); datastore.update(updateQuery, ops);
inc/dec
// 'stars'屬性增長一 ops = datastore.createUpdateOperations(Hotel.class).inc("stars"); datastore.update(updateQuery, ops); // 'stars'屬性值增長4 ops = datastore.createUpdateOperations(Hotel.class).inc("stars", 4); datastore.update(updateQuery, ops); // 'stars'屬性值減少1 ops = datastore.createUpdateOperations(Hotel.class).dec("stars"); // 和 .inc("stars", -1) 相同 datastore.update(updateQuery, ops); // 'stars'屬性值減少4 ops = datastore.createUpdateOperations(Hotel.class).inc("stars", -4); datastore.update(updateQuery, ops);
add/All
// 把一個值放入到數組中 array() (+v 0.95) // same as .add("roomNumbers", 11, false) ops = datastore.createUpdateOperations(Hotel.class).add("roomNumbers", 11); datastore.update(updateQuery, ops); // [ 11 ]
ops = datastore.createUpdateOperations(Hotel.class).set("roomNumbers", 11); datastore.update(updateQuery, ops); // 由於沒有rooNumbers數組將會引起錯誤 ops = datastore.createUpdateOperations(Hotel.class).add("roomNumbers", 11, false); datastore.update(updateQuery, ops); // causes error // 刪除roomNummbers屬性 ops = datastore.createUpdateOperations(Hotel.class).unset("roomNumbers"); datastore.update(updateQuery, ops); // use the 3rd parameter to add duplicates // add to end of array, same as add() ops = datastore.createUpdateOperations(Hotel.class).add("roomNumbers", 11, false); datastore.update(updateQuery, ops); // [ 11 ] // no change since its a duplicate... doesn't cause error ops = datastore.createUpdateOperations(Hotel.class).add("roomNumbers", 11, false); datastore.update(updateQuery, ops); // [ 11 ] // push onto the end of the array ops = datastore.createUpdateOperations(Hotel.class).add("roomNumbers", 12, false); datastore.update(updateQuery, ops); // [ 11, 12 ] // add even if its a duplicate ops = datastore.createUpdateOperations(Hotel.class).add("roomNumbers", 11, true); datastore.update(updateQuery, ops); // [ 11, 12, 11 ]
removeFirst/Last/All
//given roomNumbers = [ 1, 2, 3 ] ops = datastore.createUpdateOperations(Hotel.class).removeFirst("roomNumbers"); datastore.update(updateQuery, ops); // [ 2, 3 ] //given roomNumbers = [ 1, 2, 3 ] ops = datastore.createUpdateOperations(Hotel.class).removeLast("roomNumbers"); datastore.update(updateQuery, ops); // [ 1, 2 ] ops = datastore.createUpdateOperations(Hotel.class).removeLast("roomNumbers"); datastore.update(updateQuery, ops); // [ 1 ] ops = datastore.createUpdateOperations(Hotel.class).removeLast("roomNumbers"); datastore.update(updateQuery, ops); // [] empty array //given roomNumbers = [ 1, 2, 3, 3 ] ops = datastore.createUpdateOperations(Hotel.class).removeAll("roomNumbers", 3); datastore.update(updateQuery, ops); // [ 1, 2 ] //given roomNumbers = [ 1, 2, 3, 3 ] ops = datastore.createUpdateOperations(Hotel.class).removeAll("roomNumbers", Arrays.asList(2, 3)); datastore.update(updateQuery, ops); // [ 1 ]
Multiple Operations
你也可以在一個update指令中執行多個updae操作。
//設置城市名稱為Ottawa和是stars的增長1 ops = datastore.createUpdateOperations(Hotel.class).set("city", "Ottawa").inc("stars"); datastore.update(updateQuery, ops); //如果你在同一個屬性上執行多次同樣的指令操作,結果將會變化,即:只有最后一次有效 ops = datastore.createUpdateOperations(Hotel.class).inc("stars", 50).inc("stars"); //stars只增長1 ops = datastore.createUpdateOperations(Hotel.class).inc("stars").inc("stars", 50); //stars只增長50 //你不能在同一個屬性上執行相矛盾的操作。 ops = datastore.createUpdateOperations(Hotel.class).set("stars", 1).inc("stars", 50); //引起錯誤
在默認的驅動和shell上這是默認的行為。在Morphia中我們認為修改所有的符合條件的結果是最好的默認選擇(如下)。
{name: "Fairmont", stars: 5}, {name: "Last Chance", stars: 3}
ops = datastore.createUpdateOperations(Hotel.class).inc("stars", 50); // (+v 0.95 now takes into account the order()) // morphia 執行updateFirst方法僅僅執行第一個符合查詢條件的數據項 datastore.updateFirst(datastore.find(Hotel.class).order("stars"), ops); //僅僅修改Last Chance datastore.updateFirst(datastore.find(Hotel.class).order("-stars"), ops); // 僅僅修改 Fairmont [java] view plaincopy //default shell version is to match first //shell version has a multi to indicate to update all matches, not just first //to mimic morphia operation, set multi = false db.collection.update( criteria, objNew, upsert, multi );
createIfMissing (overload parameter)
所有的update都被重載支持一個"createIfMissing"參數。
ops = datastore.createUpdateOperations(Hotel.class).inc("stars", 50); //修改, 如果沒有找到就添加一個。 datastore.updateFirst(datastore.createQuery(Hotel.class).field("stars").greaterThan(100), ops, true); // creates { "_id" : ObjectId("4c60629d2f1200000000161d"), "stars" : 50 } //equivalent morphia shell version is... upsert = true db.collection.update( criteria, objNew, true, multi );
DAO
針對Mongo數據庫訪問,morphia提供了訪問的基本的接口便於開發人員實現。
DAO接口類:
public interface DAO<T, K>
DAO底層實現類
<span style="font-weight: normal;"><span style="font-size:12px;">package com.google.code.morphia.dao; import java.lang.reflect.ParameterizedType; import java.util.ArrayList; import java.util.List; import com.google.code.morphia.Datastore; import com.google.code.morphia.DatastoreImpl; import com.google.code.morphia.Key; import com.google.code.morphia.Morphia; import com.google.code.morphia.query.Query; import com.google.code.morphia.query.QueryResults; import com.google.code.morphia.query.UpdateOperations; import com.google.code.morphia.query.UpdateResults; import com.mongodb.DBCollection; import com.mongodb.Mongo; import com.mongodb.WriteConcern; import com.mongodb.WriteResult; /** * @author Olafur Gauti Gudmundsson * @author Scott Hernandez */ @SuppressWarnings({ "unchecked", "rawtypes" }) public class BasicDAO<T, K> implements DAO<T, K> { protected Class<T> entityClazz; protected DatastoreImpl ds; public BasicDAO(Class<T> entityClass, Mongo mongo, Morphia morphia, String dbName) { initDS(mongo, morphia, dbName); initType(entityClass); } public BasicDAO(Class<T> entityClass, Datastore ds) { this.ds = (DatastoreImpl) ds; initType(entityClass); } /** * <p> Only calls this from your derived class when you explicitly declare the generic types with concrete classes </p> * <p> * {@code class MyDao extends DAO<MyEntity, String>} * </p> * */ protected BasicDAO(Mongo mongo, Morphia morphia, String dbName) { initDS(mongo, morphia, dbName); initType(((Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0])); } protected BasicDAO(Datastore ds) { this.ds = (DatastoreImpl) ds; initType(((Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0])); } protected void initType(Class<T> type) { this.entityClazz = type; ds.getMapper().addMappedClass(type); } protected void initDS(Mongo mon, Morphia mor, String db) { ds = new DatastoreImpl(mor, mon, db); } /** * Converts from a List<Key> to their id values * * @param keys * @return */ protected List<?> keysToIds(List<Key<T>> keys) { ArrayList ids = new ArrayList(keys.size() * 2); for (Key<T> key : keys) ids.add(key.getId()); return ids; } /** The underlying collection for this DAO */ public DBCollection getCollection() { return ds.getCollection(entityClazz); } /* (non-Javadoc) * @see com.google.code.morphia.DAO#createQuery() */ public Query<T> createQuery() { return ds.createQuery(entityClazz); } /* (non-Javadoc) * @see com.google.code.morphia.DAO#createUpdateOperations() */ public UpdateOperations<T> createUpdateOperations() { return ds.createUpdateOperations(entityClazz); } /* (non-Javadoc) * @see com.google.code.morphia.DAO#getEntityClass() */ public Class<T> getEntityClass() { return entityClazz; } /* (non-Javadoc) * @see com.google.code.morphia.DAO#save(T) */ public Key<T> save(T entity) { return ds.save(entity); } /* (non-Javadoc) * @see com.google.code.morphia.DAO#save(T, com.mongodb.WriteConcern) */ public Key<T> save(T entity, WriteConcern wc) { return ds.save(entity, wc); } /* (non-Javadoc) * @see com.google.code.morphia.DAO#updateFirst(com.google.code.morphia.query.Query, com.google.code.morphia.query.UpdateOperations) */ public UpdateResults<T> updateFirst(Query<T> q, UpdateOperations<T> ops) { return ds.updateFirst(q, ops); } /* (non-Javadoc) * @see com.google.code.morphia.DAO#update(com.google.code.morphia.query.Query, com.google.code.morphia.query.UpdateOperations) */ public UpdateResults<T> update(Query<T> q, UpdateOperations<T> ops) { return ds.update(q, ops); } /* (non-Javadoc) * @see com.google.code.morphia.DAO#delete(T) */ public WriteResult delete(T entity) { return ds.delete(entity); } /* (non-Javadoc) * @see com.google.code.morphia.DAO#delete(T, com.mongodb.WriteConcern) */ public WriteResult delete(T entity, WriteConcern wc) { return ds.delete(entity, wc); } /* (non-Javadoc) * @see com.google.code.morphia.DAO#deleteById(K) */ public WriteResult deleteById(K id) { return ds.delete(entityClazz, id); } /* (non-Javadoc) * @see com.google.code.morphia.DAO#deleteByQuery(com.google.code.morphia.query.Query) */ public WriteResult deleteByQuery(Query<T> q) { return ds.delete(q); } /* (non-Javadoc) * @see com.google.code.morphia.DAO#get(K) */ public T get(K id) { return ds.get(entityClazz, id); } /* (non-Javadoc) * @see com.google.code.morphia.DAO#findIds(java.lang.String, java.lang.Object) */ public List<T> findIds(String key, Object value) { return (List<T>) keysToIds(ds.find(entityClazz, key, value).asKeyList()); } /* (non-Javadoc) * @see com.google.code.morphia.DAO#findIds() */ public List<T> findIds() { return (List<T>) keysToIds(ds.find(entityClazz).asKeyList()); } /* (non-Javadoc) * @see com.google.code.morphia.DAO#findIds(com.google.code.morphia.query.Query) */ public List<T> findIds(Query<T> q) { return (List<T>) keysToIds(q.asKeyList()); } /* (non-Javadoc) * @see com.google.code.morphia.DAO#exists(java.lang.String, java.lang.Object) */ public boolean exists(String key, Object value) { return exists(ds.find(entityClazz, key, value)); } /* (non-Javadoc) * @see com.google.code.morphia.DAO#exists(com.google.code.morphia.query.Query) */ public boolean exists(Query<T> q) { return ds.getCount(q) > 0; } /* (non-Javadoc) * @see com.google.code.morphia.DAO#count() */ public long count() { return ds.getCount(entityClazz); } /* (non-Javadoc) * @see com.google.code.morphia.DAO#count(java.lang.String, java.lang.Object) */ public long count(String key, Object value) { return count(ds.find(entityClazz, key, value)); } /* (non-Javadoc) * @see com.google.code.morphia.DAO#count(com.google.code.morphia.query.Query) */ public long count(Query<T> q) { return ds.getCount(q); } /* (non-Javadoc) * @see com.google.code.morphia.DAO#findOne(java.lang.String, java.lang.Object) */ public T findOne(String key, Object value) { return ds.find(entityClazz, key, value).get(); } /* (non-Javadoc) * @see com.google.code.morphia.DAO#findOne(com.google.code.morphia.query.Query) */ public T findOne(Query<T> q) { return q.get(); } /* (non-Javadoc) * @see com.google.code.morphia.DAO#find() */ public QueryResults<T> find() { return createQuery(); } /* (non-Javadoc) * @see com.google.code.morphia.DAO#find(com.google.code.morphia.query.Query) */ public QueryResults<T> find(Query<T> q) { return q; } /* (non-Javadoc) * @see com.google.code.morphia.DAO#getDatastore() */ public Datastore getDatastore() { return ds; } public void ensureIndexes() { ds.ensureIndexes(entityClazz); } } </span></span>
使用DAO如下:
<span style="font-weight: normal;"><span style="font-size:12px;">package com.easyway.mongodb.morphia; import java.util.List; import com.easyway.mongodb.morphia.basic.Hotel; import com.google.code.morphia.Morphia; import com.google.code.morphia.dao.BasicDAO; import com.google.code.morphia.query.UpdateOperations; import com.mongodb.Mongo; /** * 數據訪問層類的使用 */ public class HotelDAO extends BasicDAO<Hotel, String> { public HotelDAO(Morphia morphia, Mongo mongo, String dbName) { super(mongo, morphia, dbName); } /** * 統計四星級以上酒店數量 * @return */ public long countHotel(){ return count(createQuery().field("stars").greaterThanOrEq(4)); } /** * 查詢酒店 * @return */ public List<Hotel> queryHotelPhone(){ return createQuery().field("phoneNumbers").sizeEq(1).asList(); } /** * 查詢酒店 * @param hotel */ public List<Hotel> queryHotel(Hotel hotel){ return find(createQuery().filter("stars", 4).order("address.address_street")).asList(); } /** * 修改酒店信息 * @param hotel */ public void batchUpdateHotel(){ UpdateOperations<Hotel> mods = createUpdateOperations().inc("stars", 1); update(createQuery().filter("stars", 4), mods); } } </span></span>
Query
該接口能夠過濾查詢條件、排序和位移,設置查詢結果數量。實現了QueryResults 接口。
Filter
Query q = ds.createQuery(MyEntity.class).filter("foo >", 12); [java] view plaincopy Query q = ds.createQuery(MyEntity.class).filter("foo >", 12).filter("foo <", 30);
Fluent Interface
filter的方法操作,field(name)后面接條件
Query q = ds.createQuery(MyEntity.class).field("foo").equal(1); q.field("bar").greaterThan(12); q.field("bar").lessThan(40);
Validation(驗證)
驗證 屬性名和數據類型
如果在查詢中使用的屬性名在指定的java類中沒有找到將會拋出一個異常。如果一個屬性名被“.”標識連接,那么這個表達式的每個部分都將會在指定的java對象中進行驗證(有一個異常Map來記錄那個屬性 名被跳過)。
數據類型問題(比較屬性類型和參數類型)作為警告被記錄,由於服務器可能會把數據強制轉換,或者你發送意思不那么的有意義;服務器使用字節表示一些參數,所以有些類型不同的數值也可以匹配(例如數字)。
Disabling validation(是驗證無效)
通過調用disableValidation()可以使驗證變為無效,在開始等於查詢或每個查詢語句上。
Datastore ds = ... Query q = ds.createQuery(MyEntity.class).disableValidation(); //or it can be disabled for just one filter Query q = ds.createQuery(MyEntity.class).disableValidation().filter("someOldField", value).enableValidation().filter("realField", otherVal);
Sort(排序)
你可以通過一個或多個屬性名對結果進行升序或降序排序
Datastore ds = ... Query q = ds.createQuery(MyEntity.class).filter("foo >", 12).order("dateAdded"); ... // desc order Query q = ds.createQuery(MyEntity.class).filter("foo >", 12).order("-dateAdded"); ... // asc dateAdded, desc foo Query q = ds.createQuery(MyEntity.class).filter("foo >", 12).order("dateAdded, -foo"); Limit
Limit
<span style="font-size: 12px; ">Query q = ds.createQuery(MyEntity.class).filter("foo >", 12).limit(100);</span>