patternjavascriptMinor
User-like MongoDB implementation
Viewed 0 times
userimplementationmongodblike
Problem
This is my first implementation of MongoDB, much much more to come. This sheds light on some things like how I've structured my collection. I hope to gain feedback and insight from the community on best practices as well as do's and don'ts.
Givens
Example User Document
This code is the first interaction with the user they put a small piece of information in and I have to determine whether they are already in the database or not. They can initiate the signup process more than once, so both the initial and update need to write the same log.
```
users.findOne({"username":req.query.user},function(err, post){
if(typeof(post) == "undefined"){
//username does not exist in users create it with this app instance
users.save((function(){
var object = {
"username":req.query.user,
"apps":{},
};
object.apps[appAlias] = {};
object.apps[appAlias].log = [];
object.apps[appAlias].log.push({
status: "initiated-signup",
created_at: new Date(),
});
return object;
}()));
}else{
//username does exist in users create new apps object
users.update({"_id":post._id},(function(){
var object = {};
object.$push = {};
object.$push["apps."+appAlias+".log"] = {
Givens
- I have a website with multiple apps.
- Each user can at one point signup / login for an app.
- There is one MongoDB collection called
usersthat will store all the information.
- I want a log for each app that tracks users actions (signup, login, logout).
Example User Document
{
"_id": ObjectId("5035b9fc0000005eed000002"),
"apps": {
"app0": {
"log": [
{
"status": "signup",
"created_at": ISODate("2012-08-23T05:05:00.872Z")
},
{
"status": "login",
"created_at": ISODate("2012-08-23T05:05:04.012Z")
},
{
"status": "login",
"created_at": ISODate("2012-08-23T05:05:06.236Z")
}
]
}
},
"user": "reggi"
}This code is the first interaction with the user they put a small piece of information in and I have to determine whether they are already in the database or not. They can initiate the signup process more than once, so both the initial and update need to write the same log.
```
users.findOne({"username":req.query.user},function(err, post){
if(typeof(post) == "undefined"){
//username does not exist in users create it with this app instance
users.save((function(){
var object = {
"username":req.query.user,
"apps":{},
};
object.apps[appAlias] = {};
object.apps[appAlias].log = [];
object.apps[appAlias].log.push({
status: "initiated-signup",
created_at: new Date(),
});
return object;
}()));
}else{
//username does exist in users create new apps object
users.update({"_id":post._id},(function(){
var object = {};
object.$push = {};
object.$push["apps."+appAlias+".log"] = {
Solution
While I cannot comment on your Node.js code, I can tell you that we're doing something very similar on a project that uses Mongo to store every bit of information for around 200 social profiles. In our case, we're doing something like:
From my research, this is fine. Mongo's $push works great for logs like this, but be wary, it can be difficult to query data in array's like this. If you plan on doing a lot of querying against a user's app's, it may be better to store this information in a separate collection.
On the flip side, this design can be crucial if you ever need to perform any calculations with data from both your User document and the nested log. In our case, we're doing MapReduce on data from the entire document, log and all.
foreach ($videos as $video) {
$payload = ['$set' => $defaults + $meta + $this->interjectTimestamps((array)$video)];
if (isset($video['statistics'])) {
// Maintain a log of statistics for each video
$payload['$push'] = ['statistics_log' => ['execute_at_ts' => $meta['execute_at_ts'], 'statistics' => $video['statistics']]];
}
$coll->update(['_type' => 'video', 'id' => $video['id']], $payload, ['upsert' => true]);
}From my research, this is fine. Mongo's $push works great for logs like this, but be wary, it can be difficult to query data in array's like this. If you plan on doing a lot of querying against a user's app's, it may be better to store this information in a separate collection.
On the flip side, this design can be crucial if you ever need to perform any calculations with data from both your User document and the nested log. In our case, we're doing MapReduce on data from the entire document, log and all.
Code Snippets
foreach ($videos as $video) {
$payload = ['$set' => $defaults + $meta + $this->interjectTimestamps((array)$video)];
if (isset($video['statistics'])) {
// Maintain a log of statistics for each video
$payload['$push'] = ['statistics_log' => ['execute_at_ts' => $meta['execute_at_ts'], 'statistics' => $video['statistics']]];
}
$coll->update(['_type' => 'video', 'id' => $video['id']], $payload, ['upsert' => true]);
}Context
StackExchange Code Review Q#14973, answer score: 2
Revisions (0)
No revisions yet.