How to clone document to another collection? [duplicate] - javascript

My approach would be to get the document instance, and create a new one from the instance fields. I am sure there is a better way to do it.

You need to reset d1.isNew = true; as in:
Model.findById(yourid).exec(
function(err, doc) {
doc._id = mongoose.Types.ObjectId();
doc.isNew = true; //<--------------------IMPORTANT
doc.save(callback);
}
);

Can you clarify what you mean by "copy/clone"? Are you going trying to create a duplicate document in the database? Or are you just trying to have two vars in your program that have duplicate data?
If you just do:
Model.findById(yourid).exec(
function(err, doc) {
var x = doc;
Model.findById(yourid).exec(
function(err, doc2) {
var y = doc2;
// right now, x.name and y.name are the same
x.name = "name_x";
y.name = "name_y";
console.log(x.name); // prints "name_x"
console.log(y.name); // prints "name_y"
});
});
In this case, x and y will be two "copies" of the same document within your program.
Alternatively, if you wanted to insert a new copy of the doc into the database (though with a different _id I assume), that would look like this:
Model.findById(yourid).exec(
function(err, doc) {
var d1 = doc;
d1._id = /* set a new _id here */;
d1.isNew = true;
d1.save(callback);
}
);
Or if you're doing this from the outset, aka you created some document d1, you can just call save twice without setting the _id:
var d1 = new Model({ name: "John Doe", age: 54 });
d1.save(callback);
d1.save(callback);
There will now be two documents with differing _id's and all other fields identical in your database.
Does this clarify things a bit?

My two cents:
const doc = await DocModel.findById(id);
let obj = doc.toObject();
delete obj._id;
const docClone = new DocModel(obj);
await docClone.save();

So, a lot of these answers will work well for simple docs, but there could be an error case when you're trying to make a deep clone of complex documents.
If you have arrays of subdocs, for example, you can end up with duplicate _ids in your copied document, which can cause subtle bugs later.
To do a deep clone of a mongoose doc, I suggest trying something like:
//recursively remove _id fields
function cleanId(obj) {
if (Array.isArray(obj))
obj.forEach(cleanId);
else {
delete obj['_id'];
for (let key in obj)
if (typeof obj[key] == 'object')
cleanId(obj[key]);
}
}
let some_doc = await SomeModel.findOne({_id: some_id});
let new_doc_object = cleanId(some_doc.toObject());
let new_doc = new SomeModel(new_doc_object);
await new_doc.save();
This is going to be a pretty safe approach, and will ensure that every part of your object is cloned properly with newly generated _id fields on save.

The following code to clone documents:
Model.findById(yourid).exec(
function(err, doc) {
var newdoc = new Model(doc);
newdoc._id = mongoose.Types.ObjectId();
newdoc.save(callback);
}
);

For simply clone use this :
Context.findOne({
_id: context._id
})
.then(function(c) {
c._id = undefined;
c.name = context.name;
c.address = context.address;
c.created = Date.now();
return Context.create(c.toObject());
}).then(function(c) {
return res.json({
success: true,
context: context
});
}).catch(function(err) {
next(err, req, res);
});

const cloneDoc = (doc, model)=>{
const copyDoc = new Model({
...doc.toObject(),
_id: undefined,
});
copyDoc.isNew = true;
return copyDoc;
}

To copy a document into the same collection or different collection first get (query) the data and make a copy of the data. Afterwards remove the _id from the new list as you can't from the current data. This will allow you to insert a new record with new _id assigned from mongodb
change searchBy to what you are trying to find the document by.
change collectionA and collectionB to the name of the collection to create you copy to. Currently we are searching in collectionA and copying the data in collectionB
collectionA.find(searchBy).exec(function (err, doc) {
// create a new copy
let newDoc = { ...doc[0] }._doc;
// delete property from new copy (remove _id).
delete newDoc._id;
// insert copy into db
var newdoc = new collectionB(newDoc);
newdoc.save();
});

You can basically use .clone() to get a copy.
const cars = Cars.find();
const carsCopy = cars.clone();
await cars;
await carsCopy;
https://mongoosejs.com/docs/api.html#schema_Schema-clone

Related

How to delete a Firestore field inside a map that is an array element?

I would like to be able to delete varToDelete field inside a map if a condition occurs.
For some reason, the code to delete it is reached, but nothing is happening
Here is the structure of my document:
loc [
{
var1,
var2,
varToDelete
},
{
var1,
var2,
varToDelete
}
]
So, I started to think about this code:
await db.runTransaction(async (t) => {
var locRef = db.collection('documents').doc('123-456');
var locSnapshot = await locRef.get();
var loc = locSnapshot.data().loc;
loc.forEach(l => {
if (typeof l.varToDelete !== 'undefined') {
t.update(locRef, {
"varToDelete": admin.firestore.FieldValue.delete()
});
}
});
});
"varToDelete": admin.firestore.FieldValue.delete()
This will delete a field 'varToDelete' in the document itself. There is not direct method to delete a field from maps in an array. You must read the doc, remove that property from the objects and update the document with the whole new 'loc' array.
const newArr = locSnapshot.data().loc.map(({varToDelete, ...rest}) => rest)
t.update(locRef, {loc: newArr})

push to Array in async function is not filtered

var listUsers= [];
for(let item of list){
var profile = await getOne(item.updatedBy);
var gettedUsers = await User.find(queryData).populate({path: "profiles"});
var users = gettedUsers.filter(user => user._id !== profile._id);
if(users) {
for(let gettedUser of users) {
if(!listUsers.includes(gettedUser.profile._id)){
listUsers.push(gettedUser.profile._id);
// do some stuff for the getted user
}
}
}
}
console.log(listUsers); // i get duplicated users
I had added this array list 'listUsers' to filter users and then for each one of them i can do some stuff, but the problem is that i get duplicated users.
Someone could help me ?
The solution is that I changed :
listUsers.includes(gettedUser.profile._id)
to :
var contains = (list, element) => list.some(elem =>{
return JSON.stringify(element) === JSON.stringify(elem);
});
I really don't know waht's the problem but i think I was comparing objects instead of strings. Anyway this solved it ;)

'$set' is empty even though it's not

I have a problem in updating a document in MongoDB...
in the params.sendingMethodPushTime and SmsTime i receive a new Date();
tried setting the $ set inside the update function itself and tried to use hardcoded values
userScheme.statics.updateAlertSendingTimes = function (params, cb) {
var query = {uId: params.uIds};
var set = {};
if (params.alertType) {
set['alertSendingTimes'] = {};
set['alertSendingTimes'][params.alertType] = {};
set['alertSendingTimes'][params.alertType]['push'] = params.sendingMethodPushTime;
set['alertSendingTimes'][params.alertType]['sms'] = params.sendingMethodSmsTime;
var update = {
'$set': set
}
this.update(query, update, {upsert: true}, cb);
} else {
cb(null)
}
};
$set should pass and MongoDB document is updated but instead, I get $set is empty etc
EDIT: my mongoose version is 4.13.4 and my node version is 6.16 and params.alertType is a string received dynamically (in my case it's '​1' or '2')
The issue was with the scheme... it was alerts and not alert

Return list of Objects with Node js

I recently started development of a Node js application and it uses Selenium in a controller to fetch list of items from a web page and I want to return the fetched list of items as a JSON response.
exports.read_all_products = function (req, res) {
var driver = new webdriver.Builder().forBrowser('phantomjs').build();
driver.get('https://www.test.com/products?PC=' +req.params.category);
driver.wait(until.elementLocated(By.className('product-slide-all')), 20000, 'Could not locate the element within the time specified');
driver.findElements(By.className("product-slide-all")).then(function (elements) {
var arr = [];
elements.forEach(function (element) {
element.getAttribute("innerHTML").then(function (html) {
const dom = new JSDOM(html);
var obj = new Object();
obj.product_name = dom.window.document.querySelector(".product-name").textContent;
obj.product_code = dom.window.document.querySelector(".product-code").textContent;
obj.price = dom.window.document.querySelector(".product-price").textContent;
arr.push(obj);
});
});
res.json(arr);
});
}
Issue is I am always getting an empty JSON response even though items were added to the array. I want to know the proper way of handling this scenario.
Thanks.
It looks like the issue is because Selenium is running an async process, thus the response immediately returns because there is nothing blocking it.
findElements returns a Promise which you need to return the response from.
Take a look at How do I return the response from an asynchronous call?
Finally I was able to get it work with the help of webdriver.promise.map.
Moved web driver HTML extraction to separate function.
var findItems = function (category) {
var driver = new webdriver.Builder().forBrowser('phantomjs').build();
var map = webdriver.promise.map;
driver.get('https://www.test.com?PC=' + category);
driver.wait(until.elementLocated(By.className('product-slide-all')), 30000, 'Could not locate the element within the time specified');
var elems = driver.findElements(By.className("product-slide-all"));
return map(elems, elem => elem.getAttribute("innerHTML")).then(titles => {
return titles;
});
}
then call it from response handling function like bellow,
exports.read_all_products = function (req, res) {
findItems(req.params.category).then(function (html) {
var value;
var arr = [];
Object.keys(html).forEach(function (key) {
value = html[key];
const dom = new JSDOM(value);
var obj = new Object();
obj.product_name = dom.window.document.querySelector(".product-name").textContent;
obj.product_code = dom.window.document.querySelector(".product-code").textContent;
obj.price = dom.window.document.querySelector(".product-price").textContent;
arr.push(obj);
});
res.json(arr);
})
};
it's described in this stack overflow answers.

How to get only one element from an array (firebase database, nodejs)

If I use limitToLast(1), then I still get an object, with one key-value pair. To get the value, I use this code:
db.ref('/myarray').limitToLast(1).once('value').then(function(snapshot) {
var result = snapshot.val();
var lastElem;
var lastKey;
for(var i in result) {
lastElem= result[i];
lastKey = i;
break;
}
...
});
It works, but I think I do it wrong. But haven't found any better solution in the docs. How should I load only one element?
The database looks like this:
When using Firebase queries to get children, use the "child_added" event:
db.ref("/myarray")
.orderByKey() // order by chlidren's keys
.limitToLast(1) // only get the last child
.once("child_added", function(snapshot) {
var key = snapshot.key;
var val = snapshot.val();
...
});

Categories

Resources