I have a MEAN stack application.
In my database, a document has a mongo ObjectId like such :
{ "_id" : ObjectId("57e15b1009cb82cafafafd73"), "name" : "Hello", "artist_id" : "world", "year" : "2000" }
But when I load the document in my front end, the _id gets converted to a string, and my object looks like this when logged in the browser:
{ "_id" : "57e15b1009cb82cafafafd73", "name" : "Hello", "artist_id" : "world", "year" : "2000" }
What is annoying is that when I want to modify my database from my front end (update or delete an existing document), I have to convert the _id from string to ObjectId in order to target the document in my database...
So in my node application, I have to systematically massage the _id with new ObjectId(stringId) because the Id's sent by the browser are strings...
Obvisouly I'm missing out on something.
How can I make things more elegant ?
This is normal to convert string as objectId using ObjectId() because when you are passing it to web it's converted as json string so it is not an objectId anymore but when you are using an objectid from a document at your server side in that case you need not convert it to objectid.
You always need objectId() constructor if your _id type is string.
What module you use for mongodb, I think mongoose?
If you are using mongoose then you do not have to convert your _id into ObjectId, just run the query with string.
db.collection.find({_id: "57e15b1009cb82cafafafd73"});
Thanks for your replies.
So an obvious thing thats going to happen in a MEAN application, is that the ObjectIds of the documents will be converted to strings as they are consumed as JSON objects.
That's going to require heavy use of new ObjectId() when recording objects in the frontend that had their ID generated by Mongo back to the database...
Any other option than using Mongoose ? I'm very happy using the standard node mongo driver for now besides having this string conversion issue...
Related
When I'm inserting data to MongoDB it look like this..
_id: "611ddfb55c0ca9fe6df6ae6e"
name:"Residential Real Estate Photography"
price:"989"
without ObjectID,
But I wanted it to be with ObjectId
How to solve this?
The _id field in the MongoDB document is always ObjectID.
If you are talking about getting the value as an object of type ObjectID, you have to convert the string.
For js you can use https://github.com/williamkapke/bson-objectid
To get from string simply do var id = (ObjectID("611ddfb55c0ca9fe6df6ae6e"));
I am using Parse Server, which runs on MongoDB.
Let's say I have collections User and Comment and a join table of user and comment.
User can like a comment, which creates a new record in a join table.
Specifically in Parse Server, join table can be defined using a 'relation' field in the collection.
Now when I want to retrieve all comments, I also need to know, whether each of them is liked by the current user. How can I do this, without doing additional queries?
You might say I could create an array field likers in Comment table and use $elemMatch, but it doesn't seem as a good idea, because potentially, there can be thousands of likes on a comment.
My idea, but I hope there could be a better solution:
I could create an array field someLikers, a relation (join table) field allLikers and a number field likesCount in Comment table. Then put first 100 likers in both someLikers and allLikers and additional likers only in the allLikers. I would always increment the likesCount.
Then when querying a list of comments, I would implement the call with $elemMatch, which would tell me whether the current user is inside someLikers. When I would get the comments, I would check whether some of the comments have likesCount > 100 AND $elemMatch returned null. If so, I would have to run another query in the join table, looking for those comments and checking (querying by) whether they are liked by the current user.
Is there a better option?
Thanks!
I'd advise agains directly accessing MongoDB unless you absolutely have to; after all, the way collections and relations are built is an implementation detail of Parse and in theory could change in the future, breaking your code.
Even though you want to avoid multiple queries I suggest to do just that (depending on your platform you might even be able to run two Parse queries in parallel):
The first one is the query on Comment for getting all comments you want to display; assuming you have some kind of Post for which comments can be written, the query would find all comments referencing the current post.
The second query again is for on Comment, but this time
constrained to the comments retrieved in the first query, e.g.: containedIn("objectID", arrayOfCommentIDs)
and constrained to the comments having the current user in their likers relation, e.g.: equalTo("likers", currentUser)
Well a join collection is not really a noSQL way of thinking ;-)
I don't know ParseServer, so below is just based on pure MongoDB.
What i would do is, in the Comment document use an array of ObjectId's for each user who likes the comment.
Sample document layout
{
"_id" : ObjectId(""),
"name" : "Comment X",
"liked" : [
ObjectId(""),
....
]
}
Then use a aggregation to get the data. I asume you have the _id of the comment and you know the _id of the user.
The following aggregation returns the comment with a like count and a boolean which indicates the user liked the comment.
db.Comment.aggregate(
[
{
$match: {
_id : ObjectId("your commentId")
}
},
{
$project: {
_id : 1,
name :1,
number_of_likes : {$size : "$liked"},
user_liked: {
$gt: [{
$size: {
$filter: {
input: "$liked",
as: "like",
cond: {
$eq: ["$$like", ObjectId("your userId")]
}
}
}
}, 0]
},
}
},
]
);
this returns
{
"_id" : ObjectId(""),
"name" : "Comment X",
"number_of_likes" : NumberInt(7),
"user_liked" : true
}
Hope this is what your after.
This is one user's notes. I want to query and get only the notes of this use with "activeFlag:1". My query object code is
findAccountObj =
{ _id: objectID(req.body.accountId),
ownerId: req.body.userId,
bookId: req.body.bookId,
"notes.activeFlag": 1 };
But this query returns all the notes, including the ones with "activeFlag:0".
How do I fix this?
If you are on v2.2, use elementmatch operator. v3.2 and above allow aggregation and filter to return a subset of a document.
here is an example Retrieve only the queried element in an object array in MongoDB collection
I have an array of "states" in my documents:
{
"_id: ObjectId("53026de61e30e2525d000004")
"states" : [
{
"name" : "complete",
"userId" : ObjectId("52f4576126cd0cbe2f000005"),
"_id" : ObjectId("53026e16c054fc575d000004")
},
{
"name" : "active",
"userId" : ObjectId("52f4576126cd0cbe2f000005"),
"_id" : ObjectId("53026de61e30e2525d000004")
}
]
}
I just insert a new state onto the front of the array when there is a new state. Current work around until mongo 2.6 is released here: Can you have mongo $push prepend instead of append?
However I do not want users to be able to save the same state twice in row. I.E. if its already complete you should not be able to add another 'complete' state. Is there a way that I can check the first element in the array and only insert the new state if its not the same in one query/update command to mongo.
I say one query/update due to the fact that mongo does not support transactions so I don't want to query for the first element in the array then send another update statement, as that could cause problems if another state got inserted between my query and my update.
You can qualify your update statement with a query, for example:
db.mydb.states.update({"states.name":{$nin:["newstate"]}},{$addToSet:{"states":{"name":"newstate"}}})
This will prevent updates from a user if the query part of the update returns no document. You can additionally add more fields to filter on on the query part.
I have a mongo collection with documents that have a schema structured like the following:
{ _id : bla,
fname : foo,
lname : bar,
subdocs [ { subdocname : doc1
field1 : one
field2 : two
potentially_huge_array : [...]
}, ...
]
}
I'm using the ruby mongo driver that currently does not support elemMatch. I use an aggregation when extracting from subdocs via a project, unwind and match pipeline.
What I would now like to do is to page results from the potentially_huge_array array contained in the subdocument. I have not been able to figure out how to grab just a subset of the array without dragging the entire subdoc, huge array and all, out of the db into my app.
Is there some way to do this?
Would a different schema be a better way to handle this?
Depending on how huge is huge, you definitely don't want it embedded into another document.
The main reason is that unless you always want the array returned with the document, you probably don't want to store it as part of the document. How you can store it in another collection would depend on exactly how you want to access it.
Reviewing the types of queries you most often perform on your data will usually suggest the best schema - one that will allow you to be efficient about number of queries, the amount of data returned and ease of indexing the data.
If you field really huge and changes often, just placed it in separate collection.