I want to remove all members that a collection has , but I do not want to pass every member ID to .member() method .
waterline documentation explain a way to delete specific members like :
await User.removeFromCollection(3, 'pets')
.members([99,98]);
I want to have sth like :
await User.removeFromCollection(3, 'pets')
.members(['*']);
As far as I can tell, this should be done using .destroy() without a criteria.
Edit (2019-07-10): Added the empty curlies as per the comment from noobular
await User.destroy({}); // Removes all records from your User collection
await User.destroy({name:'Bill'}; // Removes all records from your User collection
where the 'name' is 'Bill'
Docs: .destroy()
Update
After you pointed out I misread your question, I came up with this solution. The docs for .removeFromCollection() states that passing in an array of parent ID's will remove all children in the specified collection, but this does not seem to function as written.
I did however find a working solution for you using .replaceCollection().
await User.replaceCollection(3, 'pets', []);
OR
await User.replaceCollection(3, 'pets').members([]);
Passing in an empty array will replace the current array of associations with the empty array, clearing out the current associations.
Docs: .replaceCollection()
Related
I have 3 subcollections nested under one another under one single main collection.
I want to get all the documents under 'colection3' for each document in 'collection2' for each document in 'collection1'
I want to query something like -
admin.firestore().collection('collection1').doc('FOR ALL DOCS IN COLLECTION 1').collection('collection2').doc('FOR ALL DOCS IN COLLECTION 2').collection('collection3').get()
My question is, can I make such query ? Will following query work ?
collection('collection1/*/collection2/*/collection3')
Is this a valid path? What does "*" indicates?
I tried something like this,
const baseRef = admin.firestore().collection(`collection1/*/collection2/*/collection3`);
const querySnap = baseRef.get()
It returned me a querySnapshot but when I tried to loop through this querySnapShot, it didn't print anything
querySnap.forEach(doc => console.log(doc.id))
output was nothing.
I was expecting that doc Ids should get printed in the console.
This can be achieved with collection group level queries.
The collectionGroup option returns all documents within the collection group you have created.
const allDocsQuery = admin.firestore()
.collectionGroup('collection1');
await allDocsQuery.get().then((snap) => {
// do operations with your data
});
Note that you will need to create a collection group in order to use this - it will throw an error with a link to the creation page, but you can also do it by following the documentation in the link above.
Background:
I have an array (A) of new objects that need to be added to an array field in Mongoose. if successful it should print to screen the newly updated object but it prints null. I checked the database and confirmed it also does not update at all. I followed the docs to use the $push and $each modifiers here:
https://www.mongodb.com/docs/manual/reference/operator/update/each/
Desired Behaviour:
I would like each object in (A) to be added to the Array field, not (A) itself. Upon success, it should print to screen the newly updated object.
Attempted Approach:
let identifier={customer:{external_id:'12345'}}
let array = [{value:30},{value:30}]
User.findOneAndUpdate(identifier,{$push:{points:{$each:array}}},{new:true})
.then((result)=>{
console.log(result)
})
Attempted Resolutions:
I tested if the issue was with the identifier parameter, but it works fine when the update parameter does not have $each (i.e. it pushes the whole array (A) into the array field)
I thought about using $addToSet like in the solution below, but as you can see in the sample code above, I want to push all objects even if they are not unique:
Mongoose - Push objects into nested array
use dot "." notation for embedded field
let filter={'customer.external_id':'12345'}
let array = [{value:30},{value:30}];
let update = { $push: { points: { $each: array } } };
User.findOneAndUpdate(filter,update,{new: true})
.then((result)=>{
console.log(result)
})
It turns out the IDs did not match. There was no issue with the code. Sorry guys.
So when creating or finding (based on reference) documents in mongodb using mongoose we use two methods to pass object id. One is simply passing the id in form of string and the other is by the mongoose.Types.ObjectId(documentId). What's the difference between them?
For better understanding see these two examples:
Option 1:
const articles = await Article.find({user: userId})
Option 2:
const articles = await Article.find({user: mongoose.Types.ObjectId(userId)}
So, do we really need to first pass it to mongoose.Types.ObjectId?
PS: I know that passing to the mongoose.types.objectId will throw an error in case if id is not an object id of MongoDB. I'm seeking if there is any other benefit of this approach or not.
const generatedEvent = await Event.create(req.body);
res.send(generatedEvent);
I am getting some data from the request body and I can generate a new Event. And I'm returning the event to client when it has generated. But I don't want to return all fields with event. I want to make filter operation like how we are using select function like this: Event.find().select({title:1,description:1})
How can i use this select func with Model.create?
If you take a look at the mongoose-source code, you can see that Model.create returns a promise with the created/inserted documents. There's no way to specify a filtering-options to return only specific fields.
Of course you could do a .find() in combination with a .select() call after creating/inserting a new record but that would result in one extra DB-query for each insert which does not make a lot of sense.
You could instead just return the desired properties from the returned document, since you know that a new document was inserted successfully with the provided data, when the promise resolved. So you could simply do:
res.send({title: generatedEvent.title, description: generatedEvent.description});
Model.create() internally doesn't fetch the document from the database, rather it actually returns the result whether it's inserted successfully or not. If successful, mongoose will return the original mongoose document that mongoose created before sending to the database.
So you could just select the fields by yourself. Using es2015 Object destructuring assignment and Object shorthand property names would help writing more concise code.
const { title, description } = await Event.create(req.body); // Object destructuring
res.send({ title, description }); // Object shorthand property names
I got a generic GET function that worps for my entire app, considering I am using just absolute documents.
Now I get to a point that I need some properties of some of my documents reference others, and when executed, the GET function populate them (obviously). For that, I need to require the referenced schema, and populate with referenced model.
The point is: I want to my GET function stay generic, so I don't want to reference any of my schemas, unless it is needed. The same goes for the .populate() method.
To achieve that, I am iterating through each key of the resulting object of the .findOne() method, and trying to check if each specific key, is or is not a ObjectId/reference or not. something like this:
require('../schemas/mySchema').findOne({'slug': req.params.slug}, function(err, doc){
console.log(mongoose.Types.ObjectId.isValid(doc[key]));
});
But the only true value it returns is for the "id"and "__v" properties (no idea where these came from... I did not set them. _id is also false), all the rest comes as false (including a given property that IS a reference, tested and working)
Is there any way to do that?
Thanks in advance
I believe mongoose returns references with the objectId nested - in the same structure as a populated object but having only the _id key. Try this:
var item = doc[key];
if (typeof item === 'object') {
console.log(mongoose.Types.ObjectId.isValid(item._id));
}