package dao;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import model.Score;
import model.UserProfile;
import org.bson.types.ObjectId;
import utils.DateUtils;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.NoSuchElementException;
/**
* nickolay, 05.05.15.
*/
public class ScoresDao {
private static final String USERS_COLLECTION = UsersDao.USERS_COLLECTION;
public static final String SCORES_FIELD_NAME = "scores";
public static final String POINTS_FIELD_NAME = "points";
private static final String DATE_FIELD_NAME = "dt";
public static final String TOTAL_POINTS_FIELD_NAME = "total_points";
public static final int TOP_INTERVAL_DAYS = 7;
private final DBCollection users;
public ScoresDao(DB db) {
this.users = db.getCollection(USERS_COLLECTION);
}
public void insert(Score score) {
DBObject newScore = new BasicDBObject();
newScore.put(POINTS_FIELD_NAME, score.getPoints());
newScore.put(DATE_FIELD_NAME, score.getDate());
BasicDBObject pushNewScore = new BasicDBObject("$push", new BasicDBObject(SCORES_FIELD_NAME, newScore));
users.update(new BasicDBObject("_id", new ObjectId(score.getUserId())), pushNewScore);
}
public List<UserProfile> getTop(int topSize) {
List<DBObject> pipeline = new ArrayList<>();
pipeline.add(new BasicDBObject("$unwind", "$" + SCORES_FIELD_NAME));
pipeline.add(getScoreDateMatch());
DBObject group = new BasicDBObject();
group.put("_id", "$" + UsersDao.USER_ID_FIELD_NAME);
group.put(TOTAL_POINTS_FIELD_NAME, new BasicDBObject("$sum", "$" + SCORES_FIELD_NAME + "." + POINTS_FIELD_NAME));
group.put(UsersDao.SOCIAL_ID_FIELD_NAME, new BasicDBObject("$first", "$" + UsersDao.SOCIAL_ID_FIELD_NAME));
group.put(UsersDao.AUTH_PROVIDER_FIELD_NAME, new BasicDBObject("$first", "$" + UsersDao.AUTH_PROVIDER_FIELD_NAME));
group.put(UsersDao.AVATAR_URL_FIELD_NAME, new BasicDBObject("$first", "$" + UsersDao.AVATAR_URL_FIELD_NAME));
group.put(UsersDao.LAST_NAME_FIELD_NAME, new BasicDBObject("$first", "$" + UsersDao.LAST_NAME_FIELD_NAME));
group.put(UsersDao.FIRST_NAME_FIELD_NAME, new BasicDBObject("$first", "$" + UsersDao.FIRST_NAME_FIELD_NAME));
pipeline.add(new BasicDBObject("$group", group));
pipeline.add(new BasicDBObject("$sort", new BasicDBObject(TOTAL_POINTS_FIELD_NAME, -1)));
pipeline.add(new BasicDBObject("$limit", topSize));
List<UserProfile> rating = new ArrayList<>();
for(DBObject ratingDbItem : users.aggregate(pipeline).results()) {
UserProfile user = new UserProfile(
ratingDbItem.get(UsersDao.USER_ID_FIELD_NAME).toString(),
ratingDbItem.get(UsersDao.FIRST_NAME_FIELD_NAME).toString(),
ratingDbItem.get(UsersDao.LAST_NAME_FIELD_NAME).toString(),
ratingDbItem.get(UsersDao.AVATAR_URL_FIELD_NAME).toString(),
(int) ratingDbItem.get(UsersDao.AUTH_PROVIDER_FIELD_NAME),
ratingDbItem.get(UsersDao.SOCIAL_ID_FIELD_NAME).toString(),
(int) ratingDbItem.get(ScoresDao.TOTAL_POINTS_FIELD_NAME)
);
rating.add(user);
}
return rating;
}
public int getPoints(String userId) {
List<DBObject> pipeline = new ArrayList<>();
pipeline.add(
new BasicDBObject("$match",
new BasicDBObject(
UsersDao.USER_ID_FIELD_NAME,
new ObjectId(userId)
)
)
);
pipeline.add(new BasicDBObject("$unwind", "$" + SCORES_FIELD_NAME));
pipeline.add(getScoreDateMatch());
DBObject group = new BasicDBObject();
group.put("_id", null);
group.put(TOTAL_POINTS_FIELD_NAME, new BasicDBObject("$sum", "$" + SCORES_FIELD_NAME + "." + POINTS_FIELD_NAME));
pipeline.add(new BasicDBObject("$group", group));
try {
DBObject result = users.aggregate(pipeline).results().iterator().next();
return (int) result.get(TOTAL_POINTS_FIELD_NAME);
} catch (NoSuchElementException e) {
return 0;
}
}
public static DBObject getScoreDateMatch() {
BasicDBObject filter = new BasicDBObject(SCORES_FIELD_NAME + "." + DATE_FIELD_NAME,
new BasicDBObject("$gte", DateUtils.offsetDays(new Date(), -TOP_INTERVAL_DAYS))
);
return new BasicDBObject("$match", filter);
}
}