1. 程式人生 > >spring data mongo使用筆記

spring data mongo使用筆記

先列提綱,後續有時間再完善

1.配置

maven依賴

 

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>

 

如果使用預設的配置一行搞定, 如果使用者名稱和密碼中有:和@符號,需要進行urlencode,@用%40替換,假如密碼是

[email protected],那麼就要寫成123%40admin,原始碼中在設定使用者名稱和密碼的時候根據:和@符號進行劈分,然後URLDecoder.decode(input, "UTF-8")

 

spring.data.mongodb.uri=mongodb://admin:[email protected]:27017/admin

 

多資料來源

 

@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class,HibernateJpaAutoConfiguration.class, MongoDataAutoConfiguration.class})

 

 

mongod.user.uri=mongodb://admin:[email protected]:27017/admin
mongod.article.uri=mongodb://admin:[email protected]:27017/article
@Configuration
@ConfigurationProperties(prefix="mongod.user")
@EnableMongoRepositories(basePackages={"com.**.repository.user"},mongoTemplateRef = "mongoUserTemplate")
public class MongoUserConfig {

    private static final Logger LOGGER = LoggerFactory.getLogger(MongoUserConfig.class);

    private String uri;

    public MongoDbFactory simpleFactory() throws Exception {
        return new SimpleMongoDbFactory(new MongoClientURI(uri));
    }

    @Bean(name="mongoUserTemplate")
    public MongoTemplate mongoUserTemplate() throws Exception {
        LOGGER.info("init mongodb template uri={}", uri);
        return new MongoTemplate(simpleFactory());
    }

    public String getUri() {
        return uri;
    }

    public void setUri(String uri) {
        this.uri = uri;
    }
}
@Data
@Configuration
@ConfigurationProperties(prefix="mongod.content")
@EnableMongoRepositories(basePackages={"com.**.repository.content"},mongoTemplateRef = "mongoContentTemplate")
public class MongoUserConfig {

    private static final Logger LOGGER = LoggerFactory.getLogger(MongoUserConfig.class);

    private String uri;

    public MongoDbFactory simpleFactory() throws Exception {
	   SimpleMongoDbFactory factory = new SimpleMongoDbFactory(new MongoClientURI(uri));
       factory.setWriteConcern(WriteConcern.MAJORITY.withJournal(true));
       return factory;
    }

    @Bean(name="mongoContentTemplate")
    public MongoTemplate mongoContentTemplate() throws Exception {
        LOGGER.info("init mongodb template uri={}", uri);
        return new MongoTemplate(simpleFactory());
    }
}

 

2.註解

 

import lombok.Data;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.annotation.Version;

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.util.Date;

@Data
public abstract class DocBase {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected String id;

    @Version
    protected Long version;

    @CreatedDate
    protected Date createdDate;

    @LastModifiedDate
    protected Date lastModifiedDate;

}

 

 

@Data
@Document(collection = "article")
@CompoundIndexes({
        @CompoundIndex(name = "article_revision_idx", def = "{ 'id' : 1, 'revision': -1}", unique = true)
})
public class Article extends DocBase{
    @Indexed
    private String userId;
	private int revision;
	private String content;
	private String articleId;
	@DBRef
	@NotNull
	private List<Attachment> attachments = Collections.emptyList();
	@Transient
    private boolean hasModifiled;
}

 

@Indexed 單一索引

@CompoundIndexes 符合索引

@DBRef 外部集合文件引用,官方說如果引用不多的話建議還是自己存一個另外一個集合文件的ID,多一次查詢

@Transient 欄位不入庫,做為處理的中間欄位

3.MongoRepository查詢和mongoTemplate

repository可以指定返回部分欄位

@Query(query="?1",fields="?2")  List<Result> findPart(Map<Object,Object> query,Map<String,Integer> fileds)

 

new Query(Criteria)

new BasicQuery(DBObject,DBObject),第二個引數可以指定返回的欄位

QueryBuilder沒有用過

 

        List<String> articleIds = Arrays.asList<>("1","2");
		List<String> fields = Arrays.asList<>("aricleId","content");
		Criteria c = Criteria.where("articleType").is("news").and("revision").is(1).and("articleId").in(articleIds);
        DBObject fieldsDB = new BasicDBObject();
        fields.forEach(s->fieldsDB.put(s,true));
        Query query = new BasicQuery(c.getCriteriaObject(),fieldsDB);
        return mongoTemplate.find(query, Question.class, collectionName);

 

分頁排序查詢,注意頁碼是從1開始,即第1頁的pageSize = 1

 Pageable pageable = new PageRequest(1, 10, new Sort(Sort.Direction.DESC, "lastModifiedDate"));

原子更新操作

mongoTemplate.updateFirst(new Query(where("id").is(counter.getId())), new Update().inc("data." + key, 1), Counter.class);

4.Convert

這裡只是記錄一下可以改變插入的資料,和讀出的資料

 

public class MongoDBConfig extends AbstractMongoConfiguration {
    @Bean
    @Override
    public CustomConversions customConversions() {
        List<Converter<?, ?>> converterList = new ArrayList<Converter<?, ?>>();
        converterList.add(new TreeReadConverter());
        converterList.add(new TreeWriteConverter());
        return new CustomConversions(converterList);
    }
}
@ReadingConverter
public class TreeReadConverter implements Converter<DBObject, Tree<?>> {
    private static final Logger LOG = LoggerFactory.getLogger(TreeReadConverter.class);
    @Override
    public Tree<?> convert(DBObject source) {
       //TODO 讀出來的時候可以自己對資料進行加工處理
	   return null;
    }
}
@WritingConverter
public class TreeWriteConverter implements Converter<Tree<?>, DBObject> {
    private static final Logger LOG = LoggerFactory.getLogger(TreeWriteConverter.class);
    @Override
    public DBObject convert(Tree<?> source) {
	    // TODO 在儲存資料的時候可以自己對資料物件進行變更
        return null;
    }
}

 

5. MongoRepository實現自定義介面

在 repositoryImpl中利用mongoTemplate實現自定義介面的方法,會自動掃描字尾Impl的類

 

interface IArticleHistory {
    Article insertToHistory(Article article);
}
public interface ArticleRepository extends MongoRepository<Question, String>, IArticleHistory {
}

 

 

import com.mongodb.BasicDBObject;
import com.mongodb.BasicDBObjectBuilder;
import com.mongodb.DBObject;
import com.mongodb.QueryBuilder;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.BasicQuery;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import javax.annotation.PostConstruct;
import javax.inject.Inject;

class ArticleRepositoryImpl implements IArticleHistory {

    private String collectionName = "articleHistory";

    @Inject
    private MongoTemplate mongoTemplate;

    @PostConstruct
    void createReleaseCollection() {
        DBObject indexKeys = BasicDBObjectBuilder.start("articleId", 1)
                .add("reVision", -1)
                .get();
        DBObject indexOptions = BasicDBObjectBuilder.start("unique", true).get();
        BasicDBObjectBuilder.start("keys", indexKeys).add("options", indexOptions).get();
        mongoTemplate.getCollection(collectionName).createIndex(indexKeys, indexOptions);
    }

    @Override
    public Article insertToHistory(Article article) {
        article.setId(null);
        mongoTemplate.insert(article, collectionName);
        return article;
    }
}

 

 

 

6.備註

mongo會自動去除空字串或者null的欄位

mongodb預設的排序有一個32M記憶體大小限制,可以通過對排序欄位增加索引或者增大32M的限制來解決,但是建議在Java層去做排序