Insert object into MongoDB object's array - javascript

I'm trying to add an object into an empty array that is stored in one of my collections.
Currently this is how I have my collection setup:
[
{
"name": "user_added",
"DRGs": []
},
...
]
How can I insert an object into the collection so that it looks like this;
[
{
"name": "user_added",
"DRGs": [
{
"code": "491",
"name": "Back & neck procedures"
}
]
},
...
]

Check out $push documentation.
You should be able to accomplish your goal with the following:
var collectionName = 'users'; // or whatever your actual collection name is
var objectToPush = {
code: "491",
name: "Back & neck procedures"
};
db.collection(collectionName).updateOne(
{"name": "user_added"},
{ $push: { "DRGS": objectToPush }}
);

Related

Filtering MongoDB collections within collection using MongoDB Shell

Apologies for the nood question. I'm just starting out using MongoDB and MongoDB Shell.
I've got a DB called Dealers that looks a little like this (very simplified):
[
{
"Id": 1,
"Vehicles": [
{
"Manufacturer": "Ford"
},
{
"Manufacturer": "MG"
},
{
"Manufacturer": "Citroen"
}
]
},
{
"Id": 2,
"Vehicles": [
{
"Manufacturer": "Ford"
},
{
"Manufacturer": "Nissan"
},
{
"Manufacturer": "Ford"
}
]
}
]
I'm trying to get my head round how you filter collections within collections EG. Say I wanted to select all the Ford's from Id 2.
I get as far as:
const dealer = database.collection('Dealers');
const result = await dealer.find({Id: 2})
and I tried:
const result = await dealers.find({
Id: 2,
Vehicles: [
{
Manufacturer: "Ford"
}
]
})
But I know that won't work because it's not iterating through the Vehicles collection. Is this the sort of instance that you would use an aggregation? Like I say, I'm very new to this sort of environment, and would really appreciate any pointers please.
I Just have tried. You can use Aggregate function To actually match the items inside the array in the collection. Like the way following query will select all the documents that have id equal to 1 and Manufacturer equal to Ford
db.MyCollection.aggregate([{$match:{Id:1}},{$unwind:"$Vehicles"}, {$match: {"Vehicles.Manufacturer":"Ford"}}]);
It is returning like this. I have used my own Id i.e equal to one you can change this.

Pushing entry into multilevel nested array in MongoDB via mongoose

I am using mongoose in nodejs(express) in backend. My array structure has THREE levels. At third level, some files are present. But I need to add entries at any level as per user demand.
[
{
"name": "A folder at",
"route": "level1_a"
},
{
"name":"Another folder at Level1",
"route": "level1_b",
"children":
[
{
"name": "A folder at Level2",
"route": "level1_b/level2_a",
"children":
[
{
"name": "A folder at Level3",
"route": "level1_b/level2_a/level3_a",
"children":
[
{
"name": "A file at last level",
"route": "level1_b/level2_a/level3_a/file1"
},
{
"name": "Add a new File",
"route":"level1_b/level2_a/level3_a/new_file"
}
]
},
{
"name": "Add Folder at Level3",
"route":"level1_b/level2_a/new_folder"
}
]
},
{
"name": "Add Folder at level2",
"route":"level1_b/new_folder"
}
]
},
{
"name": "Add Folder at Level1",
"route":"new_folder"
}
]
Now I have to add an entry at a specified position. Suppose at level2, I need to add a folder. For adding, two parameters are sent from angular to the backend. These will be 'name' and a 'route'. So my entry would be having {name: 'Products', route: 'level1_a/products'} and similarily should be placed at correct position i.e. inside the children of level1_a.
My backend has a schema which would be like:
const navSchema = mongoose.Schema({
name:{type:String,required:true},
route:{type:String},
children:{
type: {
name:{type:String,required:true},
route:{type:String},
}}
});
module.exports = mongoose.model('NatItems',navSchema);
And the API would be like:
router.post('/navlist',(req,res,next)=>{
const name= req.body.folder;
const route= req.body.url;
console.log(folder,url);//it will be required parameters like name: 'Products', route:'level1_a/products'
//let pathArray = route.split('/'); //if you want you can split the urls in the array
//Help me write the code here
res.status(201).json({
message:"Post added successfully!"
})
})
Please help me in adding entries in db. I know navlist.save() adds an entry directly but I am not able to add entries in a nested manner.
PS: I can't change the array structure because this array is easily read by angular and a complete navigation menu is made!! I am working for first time in nodejs and mongoose, so I am having difficulty in writing code with mongoose function.
For the scenario you've provided ({name: 'Products', route: 'level1_a/products'}) the update statement is pretty straightforward and looks like this:
Model.update(
{ route: "level1_a" },
{ $push: { children: {name: 'Products', route: 'level1_a/products'} } })
Things are getting a little bit more complicated when there are more than two segments in the incoming route, e.g.
{ "name": "Add a new File", "route":"level1_b/level2_a/level3_a/new_file2" };
In such case you need to take advantage of the positional filtered operator and build arrayFilters and your query becomes this:
Model.update(
{ "route": "level1_b"},
{
"$push": {
"children.$[child0].children.$[child1].children": {
"name": "Add a new File",
"route": "level1_b/level2_a/level3_a/new_file2"
}
}
},
{
"arrayFilters": [
{
"child0.route": "level1_b/level2_a"
},
{
"child1.route": "level1_b/level2_a/level3_a"
}
]
})
So you need a function which loops through the route and builds corresponding update statement along with options:
let obj = { "name": "Add a new File", "route":"level1_b/level2_a/level3_a/new_file2" };
let segments = obj.route.split('/');;
let query = { route: segments[0] };
let update, options = {};
if(segments.length === 2){
update = { $push: { children: obj } }
} else {
let updatePath = "children";
options.arrayFilters = [];
for(let i = 0; i < segments.length -2; i++){
updatePath += `.$[child${i}].children`;
options.arrayFilters.push({ [`child${i}.route`]: segments.slice(0, i + 2).join('/') });
}
update = { $push: { [updatePath]: obj } };
}
console.log('query', query);
console.log('update', update);
console.log('options', options);
So you can run:
Model.update(query, update, options);

Loop into Array of Objects comparing two arrays - PUG (Jade)

I am trying in Javascript, using PUG template (if possible), to compare two arrays and when I find a correspondance in IDs, display some particular elements.
// First Array : I iterate over "hearts" object
// Called in PUG : - const user
[
{
"hearts": [
"5e70c63a94b27b164c9b897f",
"5e723c75e4bfdf4f58c55e32"
],
"_id": "5e6bb1189978fd5afc98c57a",
"email": "catherine#catherine.com",
"name": "Catherine",
"photo": "0121b7fe-b2ae-4e75-979d-7dea1a432855.jpeg",
"__v": 0
},
{
"hearts": [
"5e723c75e4bfdf4f58c55e32"
],
"_id": "5e6bc41f5915e3d2980a5174",
"email": "marc#marc.com",
"name": "Marc",
"photo": "4caa7bfb-6408-4893-a78b-fa6e8e5b03e7.png",
"__v": 0
}
]
// Second array : I iterate over "author.hearts" object
// Called in PUG : - const store
[{
"product": {
"categories": [
1,
2
]
},
"_id": "5e6bcc76c4022eae00e22af6",
"date": "2222-02-20T21:22:00.000Z",
"author": {
"hearts": [
"5e723c75e4bfdf4f58c55e32",
"5e70c63a94b27b164c9b897f"
],
"_id": "5e6bb1189978fd5afc98c57a",
"__v": 0
},
"created": "2020-03-13T18:09:58.086Z",
"id": "5e6bcc76c4022eae00e22af6"
}]
I want to loop over the first array, find the first ID (here 5e70c63a94b27b164c9b897f), loop over the second array and see if this ID is present within the "author.hearts" object. If it is not, carry on with the second ID and if it is present, display all the keys (tags, photos, _id, date...) from the object where the ID was found.
In my example, I have just one object in my array, but I'll be having much more later on.
Many thanks for your help
If I'm understanding correctly you can do something like this. Loop through all your users and when you find their id in author.hearts stop the loop there and return the object the user's _id was found in.
var resultFound = undefined;
try {
user.forEach((el) => {
const id = el._id;
const result = store.find(el => el.author.hearts.includes(id));
if (result) {
resultFound = result;
throw resultFound;
}
});
} catch (e) {
if (e !== resultFound) {
throw e;
}
}

How to get all values of given specific keys (for e.g: name) without loop from json?

I want to fetch all the names and label from JSON without loop. Is there a way to fetch with any filter method?
"sections": [
{
"id": "62ee1779",
"name": "Drinks",
"items": [
{
"id": "1902b625",
"name": "Cold Brew",
"optionSets": [
{
"id": "45f2a845-c83b-49c2-90ae-a227dfb7c513",
"label": "Choose a size",
},
{
"id": "af171c34-4ca8-4374-82bf-a418396e375c",
"label": "Additional Toppings",
},
],
},
]
}
When you say "without loops" I take it as without For Loops. because any kind of traversal of arrays, let alone nested traversal, involve iterating.
You can use the reduce method to have it done for you internally and give you the format you need.
Try this :
const data = {
sections: [
{
id: "62ee1779",
name: "Drinks",
items: [
{
id: "1902b625",
name: "Cold Brew",
optionSets: [
{
id: "45f2a845-c83b-49c2-90ae-a227dfb7c513",
label: "Choose a size"
},
{
id: "af171c34-4ca8-4374-82bf-a418396e375c",
label: "Additional Toppings"
}
]
}
]
}
]
};
x = data.sections.reduce((acc, ele) => {
acc.push(ele.name);
otherName = ele.items.reduce((acc2, elem2) => {
acc2.push(elem2.name);
label = elem2.optionSets.reduce((acc3, elem3) => {
acc3.push(elem3.label);
return acc3;
}, []);
return acc2.concat(label);
}, []);
return acc.concat(otherName);
}, []);
console.log(x);
Go ahead and press run snippet to see if this matches your desired output.
For More on info reduce method
In the context of cJSON
yes, we can fetch the key value for any of the object.
1 - each key value is pointed by one of the objects. will simply fetch that object and from there will get the key value.
In the above case for
pre-requisition: root must contain the json format and root must be the cJSON pointer. if not we can define it and use cJSON_Parse() to parse the json.
1st name object is "sections" will use
cJSON *test = cJSON_GetObjectItem(root, "sections");
char *name1 = cJSON_GetObjectItem(test, "name" )->valuestring;
2nd name key value
cJSON *test2 = cJSON_GetObjectItem(test, "items");
char *name2 = cJSON_GetObjectItem(tes2, "name")->valuestring;
likewise, we can do for others as well to fetch the key value.

Change MongoDB find results dynamically

I'm using mongoose with node.js.
Let's say I have 'Posts' DB where each document in it is a post.
Each post has a 'ReadBy' array which holds names of users that had read this post.
When I'm searching for documents in this DB, I want to "change" the 'ReadBy' value to show by Boolean value if the user that is searching for it is in this array or not.
For example, let's say these are 2 documents that are in this DB:
{ "PostName": "Post Number 1", "ReadBy": ["Tom", "John", "Adam"] }
{ "PostName": "Post Number 2", "ReadBy": ["John", "Adam"] }
If I'm user 'Tom', I want to get the results like this:
[
{
"PostName": "Post Number 1",
"ReadBy": true,
},
{
"PostName": "Post Number 2",
"ReadBy": false,
}
]
Now, I know that I can get the documents and go over each one of them with forEach function, and then use forEach again on the "ReadBy" array and change this field.
I'm asking if there is more efficient way to do it in the mongoDB query itself, or some other way in the code.
If there is another way with mongoose - even better.
Using mongoDb $setIntersection in aggregation you get the result like this :
db.collectionName.aggregate({
"$project": {
"ReadBy": {
"$cond": {
"if": {
"$eq": [{
"$setIntersection": ["$ReadBy", ["Tom"]]
},
["Tom"]
]
},
"then": true,
"else": false
}
},
"PostName": 1
}
})
So above working first like this
{ $setIntersection: [ [ "Tom", "John", "Adam"], [ "Tom"] ] }, return [ "Tom"]
{ $setIntersection: [ [ "John", "Adam"], [ "Tom"] ] }, return [ ]
and $eq to check whether setIntersection results matched with ["Tom"] if yes then return true else false
You can try something similar to
var unwind = {"$unwind": "$ReadBy"}
var eq = {$eq: ["$ReadBy", "Bob"]}
var project = {$project: {PostName: 1, seen: eq}}
db.posts.aggregate([unwind, project])
Just notice that you solution is highly inefficient. Both for storing the data ( growing array) and for searching.

Categories

Resources