Meteor use MongoDB-collection with array of objects that already exists - mongodb

I made a python script that reads a file and creates a new mongoDB collection.
The collection is as follows, when I print one document of the collection in python:
{'_id': '5b5b0a55ca902423007413b9',
'employee': 'John Doe',
'schedule': [{'date': '08/11/2018', 'project': 'Drawing'},
...
{'date': '05/06/2018', 'project': 'Teaching'}
]
}
I made a collection in meteor using this code:
Planning = new Meteor.Collection("Planning");
Planning is also the name I gave the collection in python.
Now when I run this code in Meteor (server side):
Meteor.methods({
getFullPlanning: function(){
var one = Planning.find({ employee: 'John Doe'});
console.log(one.employee);
}
});
This piece of code logs undefined, but there is an employee with that name in my collection. What am I doing wrong in Meteor?
But this does work:
Planning.find().count() // = 53 which is correct!

According to the Meteor docs:
find returns a cursor. It does not immediately access the database or return documents. Cursors provide fetch to return all matching documents, map and forEach to iterate over all matching documents, and observe and observeChanges to register callbacks when the set of matching documents changes.
Your variable, one, is a cursor, and not the document. If you're only looking for a single document, you can call Planning.findOne({ employee: 'John Doe' }) which will return a single document, or undefined if no matches were found. You can also call Planning.find({ employee: 'John Doe' }).fetch().

Related

Pushing into sub document array inside by element

I have mongo db collection that looks like this :
({
_id:id ,
createdAt: new Date(),
name:name,
friends : [{name:"tommy",children:[{name:"sarah",age:12}]}],
dogs : [{}]
});
I would like to be able to insert a new element in the friends array if the name doesnt exist and a children element to that new array.
If i'm adding a new friend named john with a child nathaly , i'd like the output to be
({
_id:id ,
createdAt: new Date(),
name:name,
friends : [{name:"tommy",children:[{name:"sarah",age:12}]},{name:"john",children:[{name:"natahly",age:20}]}],
dogs : [{}]
});
If friend tommy already exist i would like just the children to be added to the children array and the output to now be
({
_id:id ,
createdAt: new Date(),
name:name,
friends : [{name:"tommy",children:[{name:"sarah",age:12},{name:"newchild",age:99}]},{name:"john",children:[{name:"natahly",age:20}]}],
dogs : [{}]
});
I've tried so many things already it's impossible to list.
currently i'm trying a mix of everything
// if `friends` is `[]`, push the empty children firstly through addToSet
var bulk = Directory.rawCollection().initializeUnorderedBulkOp();
bulk.find({_id: id, 'friends.name': {$exists: false}}).updateOne(
{$addToSet: {friends: {name: name_var, children: []}});
Meteor.wrapAsync(bulk.execute)();
// then Since previous step create the children array for said friend only if it doesn't already exist i'm just trying to update said friend with the new child
Directory.update(
{ _id: id,"friends.name": name_var },
{ $push: { "friends.$.children": {name:"sarah",age:12}
}}})
(i've also tried with "friends.children" instead of "friends.$.children" but i just get a different error)
And this should cover my three case but i'm having issues and i'm wondering if i'm going the right way. Any of you guys have any idea because this should at least work to add the children but it doesn't..
Errors : MongoError: The field 'friends.0.children' must be an array but is of type Object in document {_id: "0"} # when friends.$.children"
MongoError: cannot use the part (Friends of Friends.childrens) to traverse the element when friends.children"
One way of doing it would be to,
Initialize the object you want to insert/update
The object can have multiple children inserted at once.
var obj = {name:"tommy",children:[{name:"ds",age:12},{name:"two",age:12}]};
Initialize the Bulk API.
The order of operations does not matter here.
var bulk = db.t.initializeUnorderedBulkOp();
Find and update only the children records that already have a sub document for the name.
use the $addToSet operator to maintain unique records, and $each to add more than one children at a time.
bulk.find({"friends.name":obj.name})
.update({$addToSet:{"friends.$.children":{$each:obj.children}}});
Find and update those which do not have a sub document.
$push the entire object if a document doesn't have one.
bulk.find({"friends.name":{$ne:obj.name}})
.update({$push:{"friends":obj}});
bulk.execute();

Select the last document from mongo collection in meteor

I want the latest document in the query. Below I'm getting those documents whose name is coming from the variable 'personalFullName, then sorting them by a field called 'RecordID' (this field has higher numbers as later date entries), then grab the last one. I want the latest (the one with the largest RecordID number) entry in this query:
Programs.find({ FullName: personalFullName }, { sort: { RecordID: 1 }, limit: 1}).fetch().pop();
I'm getting an error that it's exceeding the call stack size.
If you are comfortable using the meteorhacks:aggregate package then you could always publish the item(s) you want using the mongo aggregate pipeline, perhaps something like this (code is coffeescript):
Meteor.publish 'latestPrograms', (personalFullName)->
return unless personalFullName?
check personalFullName, String
pipeline = [
{$match:{'Fullname': personalFullName}}
{$sort: {'RecordID': 1}}
{$group:{'_id':{Fullname: '$Fullname'}, RecordID:{$last:'$RecordID'}}}
{$limit:1}
]
#added 'latestPrograms', Random.id(), item for item in programs.aggregate pipeline
#ready()
You can then grab the data by subscribing to the latestPrograms pseudo collection. Here is an example using a iron router route:
Router.route '/home',
name: 'home'
template:'homepage'
waitOn:->
Meteor.subscribe 'latestPrograms', personalFullName
data:->
{latestPrograms: latestPrograms.find()}

Generating a new Mongo object id for each document in a collection?

How do you go about creating a unique object id for each document in a mass update?
I've tried,
db.foo.update({ objectId: null }, { $set: { objectId: new ObjectId() }}, { multi: true })
But that gives me the same object id for each document.
Because you're applying a unique value to each doc, you need to iterate over your collection and update the docs one at a time.
In the shell:
db.foo.find({ objectId: null }).forEach(function(doc) {
doc.objectId = new ObjectId();
db.foo.save(doc);
});
You cannot update multiple documents in a single command in MongoDb currently. You can update multiple documents with a common set of changes/updates, but you can not make unique changes to each document. You would need to create a loop to iterate over each document in the shell or your favorite programming language.
You can generate an object Id in MongoDB like this. You can iterate over your doc and use this mongo object id.
const ObjectId = require("mongodb").ObjectID;
const id = new ObjectId
console.log(id)

Cannot remove on mongodb using mongoose?

Hi im trying to simply remove a document from a collection using mongoose but for some strange reason I cannot get it to work.
Here is the code:
function deleteUserevent()
{console.log('in delete User Event');
models.Userevent.remove({ _id: "5214f4050acb53fe31000004"}, function(err) {
if (!err){
console.log('deleted user event!');
}
else {
console.log('error');
}
});
}
Can anyone help me out on my syntax? I know the _id is stored as new ObjectId("5214f4050acb53fe31000004") but I have tried this with no joy?
Thanks.
In MongoDB, the "_id" field of documents is of type ObjectId, as you mentioned. This is not equal to a String, so running the query
db.userevent.remove({ _id: "5214f4050acb53fe31000004"});
will not match anything, and will not remove anything. Instead, you must search for a document where the _id field is an ObjectId with that value:
db.userevents.remove({ _id: ObjectId("5214f4050acb53fe31000004")});
In mongoose, you can use the findByIdAndRemove command to remove a document with a specific _id. This command takes either an ObjectId or a String as an argument, so
query = Userevent.findByIdAndRemove("5214f4050acb53fe31000004");
should work just fine.
Just add exec() after query.
It should work like this:
await models.Userevent.findByIdAndDelete("5214f4050acb53fe31000004").exec()

Mongodb querying document with linked id

I have a document that has an id of another document from a different collection embedded in it.
My desired result is to return (I'm using python and pymongo) the all the fields of the first collection, and all of the friends from the document that was embedded.
I understand mongo doesn't do joins and I understand I'll need to make two queries. I also don't want to duplicate my data.
My question is how to piece the two queries together in python/pymongo so I have one results with all the fields from both documents in it.
Here is what my data looks like:
db.employees
{_id: ObjectId("4d85c7039ab0fd70a117d733"), name: 'Joe Smith', title: 'junior',
manager: ObjectId("4d85c7039ab0fd70a117d730") }
db.managers
{_id: ObjectId("ObjectId("4d85c7039ab0fd70a117d730"), name: 'Jane Doe', title: 'senior manager'}
desired result
x = {_id: ObjectId("4d85c7039ab0fd70a117d733"), name: 'Joe Smith', title: 'junior',
manager: 'Jane Doe' }
Your basically doing something that Mongo does not support out of the box and would actually be more painful than using the two records separately.
Basically (in pseudo/JS code since I am not a Python programmer):
var emp = db.employees.find({ name: 'Joe Smith' });
var mang = db.managers.find({ _id: emp._id });
And there you have it you have the two records separately. You cannot chain as #slownage shows and get a merged result, or any result infact since MongoDB, from one qauery, will actually return a dictionary not the value of the field even when you specify only one field to return.
So this is really the only solution, to get the the two separately and then work on them.
Edit
You could use a DBRef here but it is pretty much the same as doing it this way, only difference is that it is a helper to put it into your own model instead of doing it youself.
If it works it should be something like:
db.managers.find({
'_id' => db->employees->find({ ('_id' : 1),
('_id': ObjectId("4d85c7039ab0fd70a117d733") }))
})
updated