delete array field in a mongodb database - javascript

I am using mongoDB and my JSON (table name is "student") looks like
[{
name : "John",
subjects:["English", "Maths"]
},
{
name : "Winsel",
subjects : ["Maths"]
}]
here "subjects" is some other table and associated with student, I able to get data by using find query,
student.find({}).populate('subjects').then(function(studentData){console.log(studentData)})
by using this query i can get Data as
[{
name : "John",
subjects:["English", "Maths"]
},
{
name : "Winsel",
subjects : ["Maths"]
}]
after that i need to delete the field "subjects" which length is less than 2, I am using
if(studentData.subjects.length < 2){
delete studentData.subjects
}
but it doesn't delete the field, it shows the same result when i not using the if condition.
my expected JSON is
[{
name : "John",
subjects:["English", "Maths"]
},
{
name : "Winsel"
}]
Can any one guide me, Thanks in advance

Try this
var studentsList = [{
name : "John",
subjects:["English", "Maths"]
},
{
name : "Winsel",
subjects : ["Maths"]
}];
var newStudentList = _.map(studentsList , function(eachStudentData){
if(eachStudentData.subjects <2){
return _.pick(eachStudentData, 'name');
} else {
return eachStudentData;
}
});
You can use the newly formed students list newStudentList for your code

To remove the fields in your json response, you can use delete inside the callback function of your query function.
student.find({}).populate('subjects').then(function(studentData){
var newData = studentData;
newData.map(item => {
if(item.subjects.length < 2) {
delete item.subjects;
}
return item;
})
// you can use the newData here;
})

This works to me. I don't know if you are working with a JSON object and you need to transform it to javascript object (students.toObject()).
var students = studentsJSON.toObject();
var newStudents = students.map(studentData => {
if(studentData.subjects.length < 2) {
delete studentData.subjects;
}
return studentData;
});

try this code
var data = [{
name: "John",
subjects: ["English", "Maths"]
},
{
name: "Winsel",
subjects: ["Maths"]
}
];
console.log(data);
for (var i = 0; i < data.length; i++) {
if (data[i].subjects.length < 2) {
delete data[i].subjects;
}
}
console.log(data);

I don't know what are you trying to achieve here but populate works on application level . you can directly use aggregation pipeline for this using $project(or similar $addFields) and $lookup
db.students.aggregate(
[
{
$addFields: {
subjects:{
$cond:[{$gte:[{$size:"$subjects"},2]},"$subjects",null]
}
}
},
{
$lookup: {
"from" : "subjects",
"localField" : "subjects",
"foreignField" : "name",
"as" : "subjects"
}
},
]
);
from mongodb 3.6 you can use "$$REMOVE" instead of null in addFields stage
and also after $lookup you can use $project again to remove empty array

Related

Is it possible to update multiple documents with different values using mongo? [duplicate]

I have the following documents:
[{
"_id":1,
"name":"john",
"position":1
},
{"_id":2,
"name":"bob",
"position":2
},
{"_id":3,
"name":"tom",
"position":3
}]
In the UI a user can change position of items(eg moving Bob to first position, john gets position 2, tom - position 3).
Is there any way to update all positions in all documents at once?
You can not update two documents at once with a MongoDB query. You will always have to do that in two queries. You can of course set a value of a field to the same value, or increment with the same number, but you can not do two distinct updates in MongoDB with the same query.
You can use db.collection.bulkWrite() to perform multiple operations in bulk. It has been available since 3.2.
It is possible to perform operations out of order to increase performance.
From mongodb 4.2 you can do using pipeline in update using $set operator
there are many ways possible now due to many operators in aggregation pipeline though I am providing one of them
exports.updateDisplayOrder = async keyValPairArr => {
try {
let data = await ContestModel.collection.update(
{ _id: { $in: keyValPairArr.map(o => o.id) } },
[{
$set: {
displayOrder: {
$let: {
vars: { obj: { $arrayElemAt: [{ $filter: { input: keyValPairArr, as: "kvpa", cond: { $eq: ["$$kvpa.id", "$_id"] } } }, 0] } },
in:"$$obj.displayOrder"
}
}
}
}],
{ runValidators: true, multi: true }
)
return data;
} catch (error) {
throw error;
}
}
example key val pair is: [{"id":"5e7643d436963c21f14582ee","displayOrder":9}, {"id":"5e7643e736963c21f14582ef","displayOrder":4}]
Since MongoDB 4.2 update can accept aggregation pipeline as second argument, allowing modification of multiple documents based on their data.
See https://docs.mongodb.com/manual/reference/method/db.collection.update/#modify-a-field-using-the-values-of-the-other-fields-in-the-document
Excerpt from documentation:
Modify a Field Using the Values of the Other Fields in the Document
Create a members collection with the following documents:
db.members.insertMany([
{ "_id" : 1, "member" : "abc123", "status" : "A", "points" : 2, "misc1" : "note to self: confirm status", "misc2" : "Need to activate", "lastUpdate" : ISODate("2019-01-01T00:00:00Z") },
{ "_id" : 2, "member" : "xyz123", "status" : "A", "points" : 60, "misc1" : "reminder: ping me at 100pts", "misc2" : "Some random comment", "lastUpdate" : ISODate("2019-01-01T00:00:00Z") }
])
Assume that instead of separate misc1 and misc2 fields, you want to gather these into a new comments field. The following update operation uses an aggregation pipeline to:
add the new comments field and set the lastUpdate field.
remove the misc1 and misc2 fields for all documents in the collection.
db.members.update(
{ },
[
{ $set: { status: "Modified", comments: [ "$misc1", "$misc2" ], lastUpdate: "$$NOW" } },
{ $unset: [ "misc1", "misc2" ] }
],
{ multi: true }
)
Suppose after updating your position your array will looks like
const objectToUpdate = [{
"_id":1,
"name":"john",
"position":2
},
{
"_id":2,
"name":"bob",
"position":1
},
{
"_id":3,
"name":"tom",
"position":3
}].map( eachObj => {
return {
updateOne: {
filter: { _id: eachObj._id },
update: { name: eachObj.name, position: eachObj.position }
}
}
})
YourModelName.bulkWrite(objectToUpdate,
{ ordered: false }
).then((result) => {
console.log(result);
}).catch(err=>{
console.log(err.result.result.writeErrors[0].err.op.q);
})
It will update all position with different value.
Note : I have used here ordered : false for better performance.

Find out if an object already exists in an array

I want to do a database operation only if my barcode is new to the structure.
My plan was either to use the function includes() or simply count the existence in the array.
I have found quite helpful code snippets like countDuplicate and the function include() to do the job but I guess my case is a little bit more specific.
But I not only have an object/array which consists of strings. (1st example)
I have an object which includes different objects and their properties.
//1st example (this works pretty well)
function countDuplicate(array, elem) { //just the special type of syntax for Vue/Node.js
return array.filter(item => item == elem).length;
}
var cars = ["Saab", "Volvo", "BMW", "BMW", "BMW"];
console.log(countDuplicate(cars, "BMW"); //will return 3
console.log(cars.includes("BMW")); //will return true
But as I said I have more a structure like that:
var object = {
sub_object1: { title: "test1", barcode: "0928546725" },
sub_object2: { title: "test2", barcode: "7340845435" },
};
How can I get the same results there?
My plan was to do it like that:
if(countDuplicate(object, "0928546725") == 0)
//... do my operations
But this not work because I don't really understand how I get into the structure of my objects. I experimented with different loops but nothing actually worked.
This is my array:
export default {
data() {
return {
form: {
items: [ //Barcodes
],
status: 1,
rent_time: Date.now()
},
submit: false,
empty: false,
}
},
____________________________________________________________________
Solutions:
I tried the following from #adiga and it works for the example but not for my real case.
This is a screen of my console:
So
A simple object.filter(a => a.barcode == elem) should work - #adiga
Like that?
countDuplicateBarcodes: function(obj, elem) {
//return Object.values(obj).filter(a => a.barcode == elem).length;
return obj.filter(a => a.barcode == elem).length;
}
Doesn't work anymore...
Get all the values of object in an array usingObject.values and then use filter
function countDuplicateBarcodes(obj, elem) {
return Object.values(obj).filter(a => a.barcode == elem).length;
}
const object = {
sub_object1: { title: "test1", barcode: "0928546725" },
sub_object2: { title: "test2", barcode: "7340845435" },
sub_object3: { title: "test3", barcode: "0928546725" }
};
console.log(countDuplicateBarcodes(object, "0928546725"))
If you just want to find a barcode in your object, then your question is a duplicate of for example
https://stackoverflow.com/a/46330189/295783
Changed to match you requirement:
const barcodes = {
sub_object1: { title: "test1", barcode: "0928546725" },
sub_object2: { title: "test2", barcode: "7340845435" },
};
const findMatch = (barcode, barcodes) => JSON.stringify(barcodes).includes(`"barcode":"${barcode}"`);
console.log(
findMatch("0928546725",barcodes)
)
Looking at your code, it appears like you actually use an array of objects and not a nested object. If that's the case, something like this should work:
let scannedTools = [
{barcode: "ABC", createdAt: "today"},
{barcode: "XYZ", createdAt: "123"}
];
function isAlreadyScanned(tool) {
return scannedTools.filter(t => t.barcode == tool.barcode ).length > 0
}
console.log(isAlreadyScanned({barcode: "ABC"}));
console.log(isAlreadyScanned({barcode: "ETRASDASD"}));
console.log(isAlreadyScanned({barcode: "XYZ"}));

REACTJS: obj.push() and obj.concat is not a function

I am having an error that my obj.push() and obj.concat() is not a function but I am not so sure why. Here is my code:
onSearch = () => {
var obj = {
product: [
{
field: "is_published",
filter_value: 1
},
{
field: "order_mode",
filter_array: [
"fcfs",
"purchase-order"
]
},
{
relationship: "store",
filter_object: {
field: "slug",
filter_value: "sample"
}
}
]
}
if (this.state.search !== "") {
obj.push(
{
field: "name",
text_search: this.state.search
}
)
}
var obj2 = {
taxonomies: [
[
{ field: "type",
filter_value: "seller"
},
{ field: "slug",
filter_value: "brand"
}
]
]
}
var conc = obj.concat(obj2);
var { getProductSearch } = this.props
getProductSearch(obj.concat(obj2))
}
product and taxonomies are stored in different variables but I need to pass them as one array to getProductSearch and for that, I need to use concat(). then I need to use push() because I want to add an object to the array obj. What am I doing wrong?
The simple answer is because you can't push onto an object. Push is used for arrays.
To make this work you could instead change your code to push onto the array in your object by doing.
obj.product.push(
{
field: "name",
text_search: this.state.search
}
)
If you are trying to make product dynamic where there are multiple products like [fruits, veggies, meat] then you could change it simply by doing
onSearch(productName)
obj[productName].push(
{
field: "name",
text_search: this.state.search
}
)
This would let you call onSearch(veggies) and push only to that array if you set it up that way.

MongoDB insert record issue

I have a Mongo DB structure which looks something like this :
db.users.find().pretty();
{
"_id" : ObjectId("52b42b148ffa91f7ebbe8ebc"),
"username" : "test",
"password" : "test",
"party" : [
"4988",
"5037"
],
"something" : [
"3571"
],
"ludilo" : [],
}
Im using express js in my app and this module for connecting to Mongo https://npmjs.org/package/mongodb ,
How can I insert one entry into "something" array for user with id that I get from session.
I tried something like this , but with no success
var collection = db.collection('users');
collection.find({'_id':new ObjectID(req.user.id)}).toArray(function(err, items) {
console.dir(items);
}).insert({"something":"1234"});
You can $push a value to an array with
db.users.update(
{ _id: ObjectId( "52b42b148ffa91f7ebbe8ebc" ) },
{ $push: { something: "1234" } }
)
or if you do not want any duplicates in your array you can use $addToSet
db.users.update(
{ _id: ObjectId( "52b42b148ffa91f7ebbe8ebc" ) },
{ $addToSet: { something: "1234" } }
)
You can try this code:
collection.find({_id: new ObjectID(req.user.id)}).toArray(function(err, items) {
var doc = items[0];
doc.something.push('1234');
collection.update({_id: doc._id}, {$set: {something: doc.something}}, {safe: true}, function() {
//your next actions
});
});
I run this code on my local machine and it seems to work fine

Referencing a javascript object literal array

How would you reference the models (Accord, CRV, Prius, etc) in this structure?
Is this a bad structure to be able to extract the makes...then use a make to get the models...then use the model to get the options?
var cars = [
{
"makes" : "Honda",
"models" : [
{'Accord' : ["2dr","4dr"]} ,
{'CRV' : ["2dr","Hatchback"]} ,
{'Pilot' : ["base","superDuper"] }
]
},
{
"makes" : "Toyota",
"models" : [
{'Prius' : ["green","reallyGreen"]} ,
{'Camry' : ["sporty","square"]} ,
{'Corolla' : ["cheap","superFly"] }
]
}
];
Thanks
The structure:
var cars = [
{ name: 'Honda', models: [
{ name: 'Accord', features: ['2dr', '4dr'] },
{ name: 'CRV', features: ['2dr', 'Hatchback'] },
{ name: 'Pilot', features: ['base', 'superDuper'] }
]},
{ name: 'Toyota', models: [
{ name: 'Prius', features: ['green', 'superGreen'] },
{ name: 'Camry', features: ['sporty', 'square'] },
{ name: 'Corolla', features: ['cheap', 'superFly'] }
]}
];
I wrote about the traversal and everything else here.
cars[0].models.Accord
cars[0].models.CRV
cars[0].models.Pilot (See olliej's answer)
Though, it may be easier to use the following access concept:
cars.Honda.Accord
cars.Toyota.Prius
...using...
var cars = {
Honda : {
Accord : ["2dr", "4dr"],
CRV : ["2dr", "Hatchback"],
Pilot : ["base", "superDuper"]
},
Toyota : {
Prius : ["green", "reallyGreen"],
Camry : ["sporty", "square"],
Corolla : ["cheap", "superFly"]
}
};
Jonathan's is correct, but he missed the additional level of Array's at the model level, so it should be
cars[0].models[0].Accord
cars[0].models[1].CRV
etc
I suspect you would find it easier to use a structure along the lines of:
var cars = [
{makes : "Honda",
models : {
Accord : ["2dr","4dr"],
CRV : ["2dr","Hatchback"],
Pilot: ["base","superDuper"]
}
},
{makes :"Toyota",
models : {
Prius : ["green","reallyGreen"],
Camry : ["sporty","square"],
Corolla : ["cheap","superFly"]
}
}];
In which the models array is replaced by an object (or associative array if you like)
[edit (olliej): tidying up code in second example]
You can traverse models with this code:
for (var i = 0, carslen = cars.length; i < carslen; i++) {
for (var j = 0, modelslen = cars[i].models.length; j < modelslen; j++) {
// do something with cars[i].models[j]
}
}
but I agree with Olliej about changing the structure of your JSON to his format.
If I were you, I wouldn't lump all your data into one big multidimensional array/object literal mess like that. I'd encapsulate each object and use methods to access the data. It'll mess with your brain a lot less.

Categories

Resources