how to create user defined id in mongodb rather then _id - node.js

I have a schema to add the book details i wanted to maintain a user defined id called book_id rather than mongodb _id ,
To do that i was making a service call to find the total number documents in the collection and was increment the response by 1 and then assign to book_id
Is there a way to do it only in the server side like we use auto-increment in MySQL

you can define your own _id pattern. also you can add incremental values to _id field of a mongodb collection. but you can't use any field instead of _id. because mongodb cares _id for preventing duplication. mongodb's approach is different any rdbms. but if you want to use book_id, you can use as a field. but a mongodb collection always have _id field.
for your answer, you can read this document.
also in here you can find official mongodb sequence/auto-increment information.
you can apply this code on mongo shell.
db.book_counters.insert(
{
book_id: "bookid",
seq: 0
}
)
function getNextSequence(book) {
var ret = db.book_counters.findAndModify(
{
query: { book_id: book },
update: { $inc: { seq: 1 } },
new: true
}
);
return ret.seq;
}
db.book.insert(
{
book_id: getNextSequence("bookid"),
book: "Harry Potter"
}
)
db.book.insert(
{
book_id: getNextSequence("bookid"),
book: "LOTR"
}
)

Related

Update a value inside array of objects, inside a document in MongoDB

Here is what my collection looks like
Now suppose I have to update count of 2nd document whose reportTypes.reasonId is 300. I have access to _id as well as reasonId to update the count. I am using Mongoose to query things in my Node application.
What can I try to solve this?
You can do it via arrayFilters:
db.collection.update(
{
managerId:3
},
{
$inc:{"reportTypes.$[x].count":1}
},
{
arrayFilters:[{"x.reasonId":300 }]
}
)
playground
Explained:
Specify the matching document in the query part and create arrayFilter "x" matching the correct reportTYpes array subdocument , in the update part use the $inc operation to increment the count value in the example with 1
you should use dot notation and the $ update operator to do this:
(I'm assuming your collection is called Reason)
var conditions = {
'_id': '6244........',
'reasonTypes.reasonId': 300
}
var update = {
$inc: {
'reasonTypes.$.count': 1
}
};
Reason.update(conditions, update, function(err) {
// Handle error here
})
You can find more on the operator here mongo $ update operator

MongoDB update query in subarray

An update in the array of objects inside another array of objects.
mongodb field that I'm working on:
otherFields: values,
tasks: [
{
_id: mongodb.objectID(),
title: string,
items:[{
_id: mongodb.objectID(),
title: string,
completed: boolean //field need to be update.
}]
},
{}...
],
otherFields: value
sample mongodb document
I need to find the document using the task_id and the item_id and update a completed field in item of a task. Using the mongoose findOneAndUpdate method
const path = "tasks.$.items." + item_id + "completed";
collectionName.findOneAndUpdate(
{ _id: req.user._id, "tasks._id": taskID },
{ $set: { [path]: true }});
The above query doesn't work!!!
There is no need to use multiple query conditions, since you'd like to update a specific item that has an unique ID. Therefore you could use something along the lines:
collectionName.findOneAndUpdate(
{ 'tasks.items._id': itemID },
...
);
Keep in mind this structure is far away from optimized as it would basically look through the entire database...
Also now that I think of it, you'd also have issue with the update, as there are two nested arrays within the document. Read more here: How to Update Multiple Array Elements in mongodb

MongoDB: How to perform a second match using the results (an array of ObjectIds) of the previous match in aggregation pipeline

I have a MongoDB collection called users with documents that look like:
{
_id: ObjectId('123'),
username: "abc",
avatar: "avatar/long-unique-random-string.jpg",
connections: [ObjectId('abc'), ObjectId('xyz'), ObjectId('lmn'), ObjectId('efg')]
}
This document belongs to the users collection.
What I want to do:
First, find one document from the users' collection that matches _id -> '123'.
Project the connections field received from step 1, which is an array of ObjectIds of other users within the same collection.
Find all documents of users from the array field projected in step 2.
Project and return an array of only the username and avatar of all those users from step 3.
While I know that I can do this in two separate queries. First using findOne which returns the friends array. Then, using find with the results of findOne to get all the corresponding usernames and avatars.
But, I would like to do this in one single query, using the aggregation pipeline.
What I want to know, is it even possible to do this in one query using aggregation?
If so, what would the query look like?
What, I currently have:
await usersCollection
.aggregate([
{ $match: { _id: new ObjectId(userId) } },
{ $project: { ids: "$connections" } },
{ $match: { _id: { $in: "ids" } } },
{
$project: {
username: "$username",
avatar: { $ifNull: ["$avatar", "$$REMOVE"] },
},
},
])
.toArray()
I know this is wrong because each aggregation stage receives the results from the previous stage. So, the second match cannot query on the entire users' collection, as far as I know.
I'm using MongoDB drivers for nodeJS. And I would like to avoid $lookup for possible solutions.

How to improve the performance of query in mongodb?

I have a collection in MongoDB with more than 5 million documents. Whenever I create a document inside the same collection I have to check if there exists any document with same title and if it exists then I don't have to add this to the database.
Example: here is my MongoDB document:
{
"_id":ObjectId("3a434sa3242424sdsdw"),
"title":"Lost in space",
"desc":"this is description"
}
Now whenever a new document is being created in the collection, I want to check if the same title already exists in any of the documents and if it does not exists, then only I want to add it to the database.
Currently, I am using findOne query and checking for the title, if it not available only then it is added to the database. I am facing the performance issue in this. It is taking too much time to do this process. Please suggest a better approach.
async function addToDB(data){
let result= await db.collection('testCol').findOne({title:data.title});
if(result==null){
await db.collection('testCol').insertOne(data);
}else{
console.log("already exists in db");
}
}
You can reduce the network round trip time which is currently 2X. Because you execute two queries. One for find then one for update. You can combine them into one query as below.
db.collection.update(
<query>,
{ $setOnInsert: { <field1>: <value1>, ... } },
{ upsert: true }
)
It will not update if already exists.
db.test.update(
{"key1":"1"},
{ $setOnInsert: { "key":"2"} },
{ upsert: true }
)
It looks for document with key1 is 1. If it finds, it skips. If not, it inserts using the data provided in the object of setOnInsert.

Mongodb querying from part of object in array

Here's the sample document I'm trying to query
{
"_id":"asdf0-002f-42d6-b111-ade91df09249",
"user":[
{
"_id":"14bfgdsfg0-3708-46ee-8164-7ee1d029a507",
"n":"aaa"
},
{
"_id":"aasdfa89-5cfe-4861-8a9a-f77428158ca9",
"n":"bbb"
}
]
}
The document has 2 user references and contains the user _id and other misc information. I have the 2 user ids and am trying to get this document via only the user ids. I also don't know the order of the 2 ids. Is this a possible query?
col.findOne({
user:{
$all:[
{
_id:"14bfgdsfg0-3708-46ee-8164-7ee1d029a507"
},
{
_id:"aasdfa89-5cfe-4861-8a9a-f77428158ca9"
}
]
}
})
^^ Something that I've tried that doesn't work.
You are close with your $all attempt.
col.findOne({
"user._id":{
$all : [ "14bfgdsfg0-3708-46ee-8164-7ee1d029a507",
"aasdfa89-5cfe-4861-8a9a-f77428158ca9" ]
}
}
You can query a sub-document by wrapping it quotes. From there $all works against the values you are looking for.
Mongodb find a document with all subdocuments satisfying a condition shows a variation on this type of query.
ElemMatch should do the trick.
col.findOne({user:{$elemMatch:{"_id":"14bfgdsfg0-3708-46ee-8164-7ee1d029a507", "_id":"aasdfa89-5cfe-4861-8a9a-f77428158ca9" }}})

Resources