mongodb native driver get collection names without database name - javascript

How can I get collection names without database name from mongodb native driver for nodeJS?
db.collectionNames(function(err, collections) {
if (err) {
log.error(err);
} else {
log.info(collections);
}
});
This code returns something like this:
databaseName.collection1, databaseName.collection2, databaseName.collection3
But i want to get names: collection1, collection2, collection3

With the MongoDB 2.0.0 driver and higher, you'll need to use listCollections(), as in
db.listCollections().toArray(function(err, collections){
//collections = [{"name": "coll1"}, {"name": "coll2"}]
});

The exact structure of the response is a sub-document with the "name" key in an array:
[
{ name: 'test.cursors' },
{ name: 'test.episodes' },
{ name: 'test.zips' },
{ name: 'test.scripts' }
]
So just use map with a regex replace:
db.collectionNames(function(err, collections) {
console.log(
collections.map(function(x) {
return x.name.replace(/^([^.]*)./,"");
})
);
});
And that will strip out everything up to the first . which is the database prefix. Just in case you actually have collection names with a . in them.

Related

Unable to remove item from array using Mongoose / UpdateOne

I have a Node.js application in which I am trying to remove an object from an array when an API endpoint is hit. I so far have been unable to get it to update/remove the object. Currently, the below query returns with no error but upon checking into my DB I am still seeing it. Below is my query and basic response (I will be adding more but that is outside the scope of this question). I have also included a sample of my data model.
In the below data model I am trying to remove the whole object from the foo array as it is no longer needed.
Code
const ID = req.params.id
await FooBar.updateOne({foo: {$elemMatch: {v_code: ID}}}, { $pull: {v_code: ID}}, (err) => {
if(err) return res.json({success: false, err})
return res.json({success: true, id: ID})
})
Data model
{
bar: [
{
foo: [
{
v_code: <>
_id: <>
}
]
}
]
}
I'm sure this has been asked for in other questions but none specific to my data model. I've tried piecing together multiple SO posts and that is how I got the $elemmatch and the $pull portions of my query and so far I've had zero luck
give the following command a try:
db.collection.updateOne(
{
"bar.foo.v_code": ID
},
{
$pull: { bar: { foo: { $elemMatch: { v_code: ID } } } }
}
)
https://mongoplayground.net/p/iqJki-mnHSJ

Meteor MongoDB Setting field of array per document

I have a Documents in a Collection that have a field that is an Array (foo). This is an Array of other subdocuments. I want to set the same field (bar) for each subdocument in each document to the same value. This value comes from a checkbox.
So..my client-side code is something like
'click #checkAll'(e, template) {
const target = e.target;
const checked = $(target).prop('checked');
//Call Server Method to update list of Docs
const docIds = getIds();
Meteor.call('updateAllSubDocs', docIds, checked);
}
I tried using https://docs.mongodb.com/manual/reference/operator/update/positional-all/#positional-update-all
And came up with the following for my Server helper method.
'updateAllSubDocs'(ids, checked) {
Items.update({ _id: { $in: ids } }, { $set: { "foo.$[].bar": bar } },
{ multi: true }, function (err, result) {
if (err) {
throw new Meteor.Error('error updating');
}
});
}
But that throws an error 'foo.$[].bar is not allowed by the Schema'. Any ideas?
I'm using SimpleSchema for both the parent and subdocument
Thanks!
Try passing an option to bypass Simple Schema. It might be lacking support for this (somewhat) newer Mongo feature.
bypassCollection2
Example:
Items.update({ _id: { $in: ids } }, { $set: { "foo.$[].bar": bar } },
{ multi: true, bypassCollection2: true }, function (err, result) {
if (err) {
throw new Meteor.Error('error updating');
}
});
Old answer:
Since you say you need to make a unique update for each document it sounds like bulk updating is the way to go in this case. Here's an example of how to do this in Meteor.
if (docsToUpdate.length < 1) return
const bulk = MyCollection.rawCollection().initializeUnorderedBulkOp()
for (const myDoc of docsToUpdate) {
bulk.find({ _id: myDoc._id }).updateOne({ $set: update })
}
Promise.await(bulk.execute()) // or use regular await if you want...
Note we exit the function early if there's no docs because bulk.execute() throws an exception if there's no operations to process.
If your data have different data in the $set for each entry on array, I think you need a loop in server side.
Mongo has Bulk operations, but I don't know if you can call them using Collection.rawCollection().XXXXX
I've used rawCollection() to access aggregate and it works fine to me. Maybe work with bulk operations.

Mongo cyclic dependency detected while creating index

I have a data with structure like this:
And I try to write a query $near. For this query, I have to create index, but I get error cyclic dependency detected . Here is my code:
define model
var answers = new Schema({
countdown: String,
location: Object,
}, {
collection: 'test'
});
var Model = mongoose.model('Model', answers);
build and call query
Model.collection.createIndex({ "point": "2dsphere" });
//query = { location : { $near : [ -120.24, 39.21 ], $maxDistance: 0.10 } }
query = {
location: {
$near: {
$geometry: {
coordinates: [-120.24, 39.20 ]
},
$maxDistance: 1000
}
}
}
}
Model.find(query, function ...)
Could you please help me to solve it?..
You can use MONGO SHELL to create indices. Login with the connection string and select your DB and Collection and run
db.collection_name.createIndex({"field_name": "indexing value"})
This should solve the issue.
location.coordinates field must be an array of numbers, in your case it is an array of strings. You should change the fields type to Double.

How to update user.services for Jasmine testing in Meteor

I am trying to mock out a user for testing out my application, and I have gotten to the point where I can create a test user and log them into the mirror instance of my app.
I need to compare the gmail addresses for peoples accounts, and to test this functionality, I want to add a test email address under user.services.google.email within the Meteor users account database (which is where the accounts-google package stores it, I don't need to mock out an entire user account yet).
What I can't figure out is how to append this information, instead of just overwriting what is already there, this is what my code looks like:
if (Meteor.users.find().count() === 0) {
var testUserDetails = {
email: 'testEmail#gmail.com',
password: 'testPassword'
};
console.log("Creating the Test User");
var newUserId = Accounts.createUser(testUserDetails);
Meteor.users.update({
_id: newUserId
}, {
$set: {
services: {
google: {
email: "testEmail#gmail.com"
}
}
}
});
} else {
console.log("There are already users in the Test database");
}
console.log('***** Finished loading default fixtures *****');
},
And this is what a user looks like:
{
"_id" : "Dw2xQPDwKp58RozC4",
"createdAt" : ISODate("2015-07-30T04:02:03.261Z"),
"services" : {
"password" : {
"bcrypt" : "asdfasdfasdfdsafsadfasdsdsawf"
},
"resume" : {
"loginTokens" : [ ]
}
},
"emails" : [
{
"address" : "testEmail#gmail.com",
"verified" : false
}
]
}
Now $set just rewrites everything within services, and there is no $push operation for mongo or for js, so how should I go about doing this? Should I consume the object and parse it manually?
*Note I have also tried using Meteor's Accounts.onCreateUser(function(options, user) but facing the same issue.
[...] there is no $push operation for mongo [...]
Sure, there is a $push operator, which appends a specified value to an array.
However, I think what you are trying to do is to update a document and keep all values which are already set.
Here is how you can do that:
Query the document first to get the object you want to set.
Update the respective object.
Run the MongoDB update operation to set the new object.
For instance:
var user = Meteor.users.findOne({
_id: newUserId
});
var servicesUserData = user.services;
servicesUserData.google.email = "your_new_email#gmail.com";
Meteor.users.update({
_id: newUserId
}, {
$set: {
"services": {
servicesUserData
}
}
});

Meteor publish-composite and nested collection

I am trying to build an app that has a many to many relationship in Meteor. There will be jobs, clients and users collections. Clients can have multiple jobs, and most importantly multiple users can work on the same job.
I have the jobs collection set up as follows in my fixtures file:
Jobs.insert({
jobNum: 'Somejob',
clientId: 'XXXXXXXX',
clientName: 'Some Client',
rate: XX,
userNames: [
{userId: user1._id},
{userId: user2._id}
],
active: true
});
I am publishing according to the readme for publish-composite, but I cannot get the users to publish to the client. Here is the publication code:
Meteor.publishComposite('jobsActive', {
find: function() {
// Find all active jobs any client
return Jobs.find({active: true});
},
children: [
{
find: function (job) {
// Return a client associated with the job
return Clients.find({_id: job.clientId});
}
},
{
find: function (job) {
// Return all users associated with the job
// This is where the problem is
return Meteor.users.find({_id: job.userNames.userId});
}
}
]
});
I can't figure out how to correctly find over an array. I tried a number of things and nothing worked. Is this possible? Or do I need to go about this in another way? I've thought about referencing jobs in the users collection, but there will be far more jobs than users, so it seems to make more sense like this.
BTW, I did subscribe to 'jobsActive' as well. The other two collections are coming over to the client side fine; I just can't get the users collection to publish.
Thanks for any help and ideas.
job.userNames.userId doesn't exist in your collection. job.userNames is an array of objects which have the key userId.
Try something like _.map( job.userNames, function( users ){ return users.userId } ).
Your code will be:
Meteor.publishComposite('jobsActive', {
find: function() {
return Jobs.find({active: true});
},
children: [
{
find: function (job) {
return Clients.find({_id: job.clientId});
}
},
{
find: function (job) {
return Meteor.users.find({ _id: { $in: _.map( job.userNames, function( users ) { return users.userId } ) } });
}
}
]
});
I think you don't need publish-composite at all, try this code snippet. It works for me!
Meteor.publish('jobsActive', function () {
return Events.find(
{
$or: [
// { public: { $eq: true } },
{ active: true },
{ userNames: this.userId}
],
},
{
sort: {createdAt: -1}
}
);
});

Categories