MongoDB, issue while iterating over a cursor [duplicate] - mongodb

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 6 years ago.
I am not able to understand why the inserted MongoDB document although it contains items, the code is not able to iterate over. The cursor object itself is not null. I am able to retrieve the documents using db.newmongo.find()
var url = 'mongodb://localhost:27017/test';
MongoClient.connect(url, function(err, db) {
db.collection("newmongo").insert([{"name": "XXX", "age": "50"},
{"name": "YYY", "age": 43},
{"name": "ZZZ", "age": 27},
{"name": "AAA", "age": 29},
{"name": "BBB", "age": 34}]);
console.log("Connected correctly to server.");
var cursor=db.collection('newmongo').find();
console.log(cursor); // This gets logged
cursor.each(function(err, doc) {
if (doc != null) {
console.log('Document found');
} else {
console.log('Document not found');
}
});

You should always check if the records were inserted correctly without any errors. To do that you must pass a callback to the insert method. Something like this :
var url = 'mongodb://localhost:27017/test';
MongoClient.connect(url, function(err, db) {
if(err){
console.log("Error connecting to MongoDB");
return;
}
console.log("Connected correctly to server.");
db.collection("newmongo").insert([{name: "XXX", age: 50},
{name: "YYY", age: 43},
{name: "ZZZ", age: 27},
{name: "AAA", age: 29},
{name: "BBB", age: 34}], function(err, docs){
if(err){
console.log("Error inserting documents in MongoDB : " + JSON.stringify(err));
}
if(docs){
console.log("Following Documents were Successfully Inserted : \n" + JSON.stringify(docs));
}
});
Also since this is an async call, it will not wait till the inserting of documents is done and will fire the find instantly. Due to this, you might not be able to get any records in the newmongo collection as the write operation is still in progress.
So what I suggest is to call find only after the if(docs) condition.
And I also think that calling find is not necessary as the docs parameter that was returned in the callback would return the docs successfully written in your collection. So you can directly log them to console as shown in the above example.

Related

insert element into db only if it doesnt exist

Hy i am using mongoose.
I have this query that inserts about 30 elements into my database:
await Code.insertMany(information);
Information looks like:
[
{
discount: 20,
url: '...',
code: "...",
sponsorUrl: "...",
sponsorAccount: "..."
},
]
The url is unique. I want to add again 30 items into the database but it could be that 10 items from 30 are already saved in the database
How can i achieve that? I could loop it but is there an better solution?
I dont want to have duplicated urls
The upsert = true option creates the object if the url does not already exist in a document in the collection.
for (var i of information){
Code.update(
{'url' : i.url },
{$set : i},
{upsert : true, multi : true},
function(err, doc){
if(err) throw err;
console.log(doc);
}
)
}

can't update DB using put request in express.js

I'm trying to update the languages_known through post request to the mongodb collection using the body of the request but its not updating i'm newbie any help would be really appreciated.
mongodb document :
{
"_id": {
"$oid": "5d63e81c342987154cdc698e"
},
"name": "anjana",
"email": "anju#gmail.com",
"age": "22",
"languages_known": [
"Bengali",
"Kannada"
],
"phone": "684684684846"
}
server code :
app.put('/students/add',function(req,res){
var myobj={
$set:{_id:require('mongodb').ObjectID(req.body.id),languages_known:req.body.remove}
}
db.collection('students').updateOne({languages_known:req.body.add},myobj,function(err,result){
if(err){throw err}
console.log("updated")
})
})
request body :
{
"id":"5d63e81c342987154cdc698e",
"remove": ["Bengali", "Kannada"],
"add": ["Tamil", "Punjabi"]
}
I've expected to update the languages_known field using this req through postman to this id
Ok this issue is with the query, you can't update _id of a document like that, also as your requirement is not to do that, Please try this :
server code :
// replace languages_known with new languages based on _id, in case if you wanted to update the array you can use $push
app.put('/students/add', function (req, res) {
const id = require('mongodb').ObjectID(req.body.id)
let updateQuery = {
$set: { languages_known: req.body.add }
}
db.collection('students').updateOne({ _id: id }, updateQuery, function (err, result) {
if (err) { throw err }
console.log("updated")
})
})

Return Array of Populated Objects in Mongoose

I have a DB for a forum with 3 collections: Threads, Posts, Comments.
I have a GET request to return an individual forum thread that populates each thread with user's posts, and each user post with any comments that were made on it which is working as shown below:
router.get('/:id', (req, res) => {
Threads
.findById(req.params.id)
.lean()
.populate({path: 'posts'})
.exec(function(err, docs){
var options = {
path: 'posts.comments',
model: 'comments'
};
if(err) return res.json(500);
Threads.populate(docs, options, function(err, thread){
res.json(thread);
})
})
})
When this GET request is made it will return a forum thread like so:
{
"_id": "5924ad549a08ed4e70a9c89f",
"title": "Testing Full Schemas",
"author": "Mongoose",
"content": "Schema Content",
"posts": [
{
"_id": "5924ad999a08ed4e70a9c8a0",
"content": "New Schema Post",
"user": "Mongodb",
"comments": [
{
"_id": "5924ae489a08ed4e70a9c8a1",
"comment": "New Schema Content",
"user": "Matt",
"likes": 0,
"created": "2017-05-25T12:41:58.319Z"
}
]
}
Now I need a GET request to return an array of ALL threads (router.get('/')) with each threads posts and comments to be populated. I tried to replace:
Threads
.findById(req.params.id)
with
Threads
.find(req.params.id)
but it is not working. Does anyone have an idea of how this could be accomplished?
To return all the threads, simply use find without any match condition in it.
Also, populate posts and 'posts.comment' in the find query itself, you don't need to do it in the callback of the find.
use population across multiple levels
**Try this:
Threads.find({})
.populate({
path:'posts',
populate :{
path : comments
}
})
.exec(function(err,docs){
//docs is the array of all the Threads, with posts and comments populated within it
})
Read Mongoose Documentation on Populate and Nested Population for detailed information. ( Search for Populating across multiple levels)
findById and findOne returns a single document, where find returns a cursor. Once you go through the cursor of find, you are at the end, and there are no more documents.
Using find query:-
ModelName.find({_id:req.params.id})
.populate({
path:'posts',
populate :{
path : comments
}
},(error,data)=>{
if(error){
res.json(error);
}
else{
res.json(data);
}
})
Using findById query:-
ModelName.findById(req.params.id)
.populate({
path:'posts',
populate :{
path : comments
}
},(error,data)=>{
if(error){
res.json(error);
}
else{
res.json(data);
}
})

Mongoose findOne and save new document [duplicate]

This question already has answers here:
pushing object into array schema in Mongoose
(2 answers)
Closed 6 years ago.
I have a list of users that has 'hobby' object inside it.
User: {
name: John Doe,
hobby: {
[{hobby_id: 77777, hobby_name: hockey, hobby_type: sports}],
[{hobby_id: 88977, hobby_name: singing, hobby_type: talent}],
}
age: 27
}
now i want to findOne the user and add new hobby on the list. my first try is:
var user = User.findOne({ _id : req.body.user_id});
User.update(user, { hobby: [{ hobby_name: req.body.name ,
hobby_type: req.body.type }] },
function(err, user){
if(err){
return res.status(500).json(err);
}else{
return res.status(200).json(user);
}
});
however, with this code, everytime i call the function, my "NEW" hobby replaces the first one.
what can i do?
You can use the following code to do the same.
User.findByIdAndUpdate(req.body.user_id, {$push:{ hobby: [{ hobby_name: req.body.name ,
hobby_type: req.body.type }] }}, {safe: true}
function(err, user){
if(err){
return res.status(500).json(err);
}else{
return res.status(200).json(user);
}
});
And here findByIdAndUpdate is do both finding and updating the same document. no need to use callback or promises. Please refer the following link.
Your problem is that you are using whe repalce syntax, rather than the update syntax. I think you need:
user.hobbies.push({ hobby_name: req.body.name ,
hobby_type: req.body.type })

meteor query for all documents with unique field

I want to do exactly what this SO question gets at but with Meteor on the server side:
How do I retrieve all of the documents which HAVE a unique value of a
field?
> db.foo.insert([{age: 21, name: 'bob'}, {age: 21, name: 'sally'}, {age: 30, name: 'Jim'}])
> db.foo.count()
3
> db.foo.aggregate({ $group: { _id: '$age', name: { $max: '$name' } } }).result
[
{
"_id" : 30,
"name" : "Jim"
},
{
"_id" : 21,
"name" : "sally"
}
]
My understanding is that aggregate is not available for Meteor. If that is correct, how can I achieve the above? Performing post-filtering on a query after-the-fact is not an ideal solution, as I want to use limit. I'm also happy to get documents with a unique field some other way as long as I can use limit.
There is a general setup you can use to access the underlying driver collection object and therefore .aggregate() without installing any other plugins.
The basic process goes like this:
FooAges = new Meteor.Collection("fooAges");
Meteor.publish("fooAgeQuery", function(args) {
var sub = this;
var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
var pipeline = [
{ "$group": {
"_id": "$age",
"name": { "$max": "$name" }
}}
];
db.collection("foo").aggregate(
pipeline,
// Need to wrap the callback so it gets called in a Fiber.
Meteor.bindEnvironment(
function(err, result) {
// Add each of the results to the subscription.
_.each(result, function(e) {
// Generate a random disposable id for aggregated documents
sub.added("fooAges", Random.id(), {
"age": e._id,
"name": e.name
});
});
sub.ready();
},
function(error) {
Meteor._debug( "Error doing aggregation: " + error);
}
)
);
});
So you define a collection for the output of the aggregation and within a routine like this you then publish the service that you are also going to subscribe to in your client.
Inside this, the aggregation is run and populated into the the other collection ( logically as it doesn't actually write anything ). So you then use that collection on the client with the same definition and all the aggregated results are just returned.
I actually have a full working example application of a similar processs within this question, as well as usage of the meteor hacks aggregate package on this question here as well, if you need further reference.