I'm working in a project oj NodeJS, and I want to delete an element of array containing objets.
The Schema is:
{
"products" : [
{
"productid" : 1,
"name" : "product 1",
"price" : 200
},
{
"productid" : 2,
"name" : "product 2",
"price" : 300
},
{
"productid" : 3,
"name" : "product 3",
"price" : 350
},
{
"productid" : 4,
"name" : "product 4",
"price" : 300
},
,
{
"productid" : 5,
"name" : "product 5",
"price" : 300
}
]
}
And i want to delete product 3, how is query in mongodb? the "productid" attribute is key, does not repeat it
Thanks.
Use this:
Change collection name and {} as per your need.
db.collection.update( {}, { "$pull" : { "products" : { "productid" : 3 } } });
if it matches multiple element then use multi option like
db.collection.update( {}, { "$pull" : { "products" : { "productid" : 3 } } },
{ multi: true });
db.collection.update( {<query>}, { "$pull" : { "products.productid" : 3 } });
Related
Suppose that I have a collection with documents like below
{
"location" : "Tokyo",
"region" : "Asia",
"attraction": {
"transportation" : "Subway",
"food" : {
"food_0" : {
"name" : "Sushi",
"price" : 100,
"restaurant" : "Ookinza"
},
"food_1" : {
"name" : "Sashimi",
"price" : 200,
"restaurant" : "Hibiki"
},
"food_2" : {
"name" : "N/A",
"price" : "N/A",
"restaurant" : "N/A"
}
}
}
},
{
"location" : "Taipei",
"region" : "Asia",
"attraction": {
"transportation" : "Subway",
"food" : {
"food_0" : {
"name" : "Bubble tea",
"price" : 50,
"restaurant" : "The Alley"
},
"food_1" : {
"name" : "Oyster cake",
"price" : 100,
"restaurant" : "Night market"
},
"food_2" : {
"name" : "N/A",
"price" : "N/A",
"restaurant" : "N/A"
}
}
}
},
{
"location" : "Toronto",
"region" : "North America",
"attraction": {
"transportation" : "Uber",
"food" : {
"food_0" : {
"name" : "Raman",
"price" : 300,
"restaurant" : "Kinto"
},
"food_1" : {
"name" : "Bubble tea",
"price" : 200,
"restaurant" : "Fresh Fruit"
},
"food_2" : {
"name" : "N/A",
"price" : "N/A",
"restaurant" : "N/A"
}
}
}
},
How do I find documents that have matching field in the child object of Food?
i.e. If I want to find document that has restaurant:"Fresh Tea"?
Currently what I have:
app.get(route, (req, res) => {
var detail = {};
if(req.query.location){
detail['location'] = req.query.location.toUpperCase();
}
if(req.query.region){
detail['region'] = req.query.region.toUpperCase();
}
if(req.query.transportation){
detail['attraction.transportation'] = new RegExp(req.query.transportation.split(","), "i"),
}
if(req.query.restaurant){
detail['attraction.food.food_0'] = req.query.restaurant;
}
db.collection(config.dbCollections.foodDB)
.aggregate([
$match: detail,
},
{
$lookup: {
... // code continues
Right now detail['attraction.food.food_0'] = req.query.restaurant is only able to find document that has matching food_0.restaurant, but I still can't find a way to make it check all child objects within "food".
Updated with more info:
User has the option to enter multiple search categories, and I want to combine all the search requests into "detail" and find all matching results. I.e. If user looks for transportation="Subway" and food="Bubble tea", then both Taipei and Toronto should come up as result.
Using dynamic value as field name is generally considered as anti-pattern and should be avoided. Nevertheless, you can convert the object attraction.food to an array of k-v tuple and perform the search with your criteria. For your case, $anyElementTrue with $map will help with processing the array.
db.collection.aggregate([
{
"$addFields": {
"test": {
"$anyElementTrue": {
"$map": {
"input": {
"$objectToArray": "$attraction.food"
},
"as": "t",
"in": {
$or: [
{
$eq: [
"$$t.v.transportation",
"Subway"
]
},
{
$eq: [
"$$t.v.name",
"Bubble tea"
]
}
]
}
}
}
}
}
},
{
$match: {
test: true
}
},
{
"$unset": "test"
}
])
Here is the Mongo Playground for your reference.
A possible aggregation pipeline
Add a temporary field using $addFields and $objectToArray which does something similar to javascript Object.entries()
Do the matching
Remove the added temporary field using $project 0
playground
db.collection.aggregate([
{
"$addFields": {
"foodArray": {
"$objectToArray": "$attraction.food"
},
},
},
{
"$match": {
"foodArray.v.restaurant": "Fresh Fruit"
}
},
{
"$project": {
"foodArray": 0
},
},
])
This is my database collection:
{"productId" : 1,
"isVariant": 1,
"isComplete" : 1,
"variantId" : 1,
"attributeSet" : [
{
"name" : "Capacity",
"value" : "500 GB",
"id" : 3
},
{
"name" : "Form Factor",
"value" : "5 inch",
"id" : 4
},
{
"id" : 5,
"name" : "Memory Components",
"value" : "3D NAND",
"isVariation" : 0
}
]
},
{"productId" : 2,
"isVariant": 1,
"isComplete" : 1,
"variantId" : 1,
"attributeSet" : [
{
"name" : "Capacity",
"value" : "1 TB",
"id" : 3
},
{
"name" : "Form Factor",
"value" : "5 inch",
"id" : 4
},
{
"id" : 5,
"name" : "Memory Components",
"value" : "3D NAND",
"isVariation" : 0
}
]
},
{"productId" : 3,
"isVariant": 1,
"isComplete" : 0,
"variantId" : 1,
"attributeSet" : [
{
"name" : "Capacity",
"value" : "500 GB",
"id" : 3
},
{
"name" : "Form Factor",
"value" : "2.5 inch",
"id" : 4
},
{
"id" : 5,
"name" : "Memory Components",
"value" : "3D NAND",
"isVariation" : 0
}
]
},
{"productId" : 4,
"isVariant": 1,
"isComplete" : 0,
"variantId" : 1,
"attributeSet" : [
{
"name" : "Capacity",
"value" : "1 TB",
"id" : 3
},
{
"name" : "Form Factor",
"value" : "2.5 inch",
"id" : 4
},
{
"id" : 5,
"name" : "Memory Components",
"value" : "3D NAND",
"isVariation" : 0
}
]
}
Now I want to send the data of only the attribute where isVariation is not 0. Also I want to send the variant values of each attribute where isComplete =1. Hence the result should look like this
result : [{
"id": 3,
"name": "Capacity",
"value": [
"500 GB",
"1 TB"
]
}, {
"id": 4,
"name": "Form Factor",
"value": [
"5 inch"
]
}]
The above result does not have value of 2.5 inch as the isComplete is 0 for this document. Can anyone help me with the query
$match isComplete is 1
$project to show required fields
$unwind deconstruct attributeSet array
$match attributeSet.isVariation is not 0
$group by attributeSet.id and get first name and get unique value using $addToSet
db.collection.aggregate([
{ $match: { isComplete: 1 } },
{
$project: {
_id: 0,
attributeSet: 1
}
},
{ $unwind: "$attributeSet" },
{ $match: { "attributeSet.isVariation": { $ne: 0 } } },
{
$group: {
_id: "$attributeSet.id",
name: { $first: "$attributeSet.name" },
value: { $addToSet: "$attributeSet.value" }
}
}
])
Playground
The $project stage is not required in your query, i have added because this will optimize your query performance.
I'm able to do
db.getCollection('comps').find({"stats.cat3.detail.name" : "Friendlyness"})`
This shows the proper docs the have a name of "Friendlyness" in the detail array.
I wanted to change "Friendlyness" to "friendliness"
I tried :
db.getCollection('comps').update(
{"stats.cat3.detail.name" : "Friendlyness"},
{$set : {"stats.cat3.detail.name" : "Friendliness"} }
)
and got errors like
" cannot use the part (stats of stats.cat3.detail.name) to traverse the element ({stats: [ { cat3: ...."
I tried putting in position operators "$" all over the update object property. but still get errors.
sample data:
{
"_id" : ObjectId("58d94c441eb9e52454932db6"),
"desc" : "Manufacturer of a wide range of consumer electronics products including audio, video, communications, and computer systems.",
"source" : "alexa",
"category" : "Consumer Electronics",
"name" : "comp1.com",
"__v" : 0,
"stats" : [
{
"cat1" : {
"detail" : [
{
"value" : [
{
"data" : 1,
"name" : "quick service"
}
],
"name" : "Time on hold"
},
{
"value" : [
{
"data" : 1,
"name" : "some words but strong accent"
},
{
"data" : 1,
"name" : "EZ to understand"
}
],
"name" : "Language fluency"
},
{
"value" : [
{
"data" : 1,
"name" : "Yes"
}
],
"name" : "Human answered"
},
{
"value" : [
{
"data" : 2,
"name" : "Like a hot potato"
},
{
"data" : 1,
"name" : "1 or 2 times"
}
],
"name" : "Transfered alot"
},
{
"value" : [
{
"data" : 3,
"name" : "ok time"
},
{
"data" : 1,
"name" : "quick service"
},
{
"data" : 1,
"name" : "short time"
}
],
"name" : "Time on Hold"
},
{
"value" : [
{
"data" : 1,
"name" : "some word but strong accent"
},
{
"data" : 2,
"name" : "EZ to understand"
}
],
"name" : "Language Fluency"
},
{
"value" : [
{
"data" : 2,
"name" : "Yes"
}
],
"name" : "Human Answered"
}
],
"average" : 81
},
"cat2" : {
"detail" : [
{
"value" : [
{
"data" : 1,
"name" : "It was ok"
},
{
"data" : 1,
"name" : "Not EZ at all"
},
{
"data" : 7,
"name" : "there were hidden gimicks"
},
{
"data" : 2,
"name" : "It was OK"
},
{
"data" : 1,
"name" : "Found Quickly"
}
],
"name" : "Easy to find desired product"
},
{
"value" : [
{
"data" : 1,
"name" : "Easy to understand"
},
{
"data" : 1,
"name" : "Eventually understood"
}
],
"name" : "Clear information about the product"
},
{
"value" : [
{
"data" : 2,
"name" : "none"
},
{
"data" : 3,
"name" : "There was but won't complain"
},
{
"data" : 1,
"name" : "Very Bad"
}
],
"name" : "Annoying popups"
},
{
"value" : [
{
"data" : 4,
"name" : "Eventually Understood"
},
{
"data" : 1,
"name" : "EZ to understand"
}
],
"name" : "Clear data about the product"
}
],
"average" : 71
},
"cat3" : {
"detail" : [
{
"value" : [
{
"data" : 1,
"name" : "Very quick"
}
],
"name" : "Prompteness"
},
{
"value" : [
{
"data" : 3,
"name" : "We're cool"
},
{
"data" : 4,
"name" : "They didn't like me"
}
],
"name" : "Friendlyness"
},
{
"value" : [
{
"data" : 3,
"name" : "Very Confusing"
},
{
"data" : 2,
"name" : "Still a little confused"
},
{
"data" : 3,
"name" : "Enlightened"
}
],
"name" : "Knowledge"
},
{
"value" : [
{
"data" : 3,
"name" : "On hold too many times"
}
],
"name" : "Promptness"
}
],
"average" : 69
}
}
]
}
I need to convert a collection with nested documents to a model tree structure with parent references. So this is how my structure looks like:
{
"_id" : "sdaGREsfRdfGdFdwG",
"docTitle" : "Document 1",
"group" : [
{
"id" : "cdPhkTpMXi8z6TqMT"
"title" : "title 1",
"data" : [
{
"id" : "Nkspf5kKfPo3axeJA",
"some" : "data",
"other" : "things",
"and" : "so on",
},
{
"id" : "Ca8ncFgq83RoeD8he",
"some" : "data",
"other" : "things",
"and" : "so on",
},
{
"id" : "vyjgkuNXRN9KkCd5o",
"some" : "data",
"other" : "things",
"and" : "so on",
}
],
},
{
"id" : "TuibXPe5qMvqdMW6q"
"title" : "title 2",
"data" : [
{
"id" : "f5L5zsSNRSQKWoAXL",
"some" : "data",
"other" : "things",
"and" : "so on",
}
],
}
]
}
As you can see, there is a group array, which has also a data array. Now I need a main document like this:
{
"_id" : "sdaGREsfRdfGdFdwG",
"docTitle" : "Document 1"
}
And the next child elements, which would be:
{
"id" : "cdPhkTpMXi8z6TqMT"
"title" : "title 1",
"type" : "group",
"parent" : "sdaGREsfRdfGdFdwG"
},
{
"id" : "TuibXPe5qMvqdMW6q"
"title" : "title 2",
"type" : "group",
"parent" : "sdaGREsfRdfGdFdwG"
}
At least the data elements, which are children of the group-elements:
{
"id" : "Nkspf5kKfPo3axeJA",
"some" : "data",
"other" : "things",
"and" : "so on",
"type" : "element",
"parent" : "cdPhkTpMXi8z6TqMT"
},
{
"id" : "Ca8ncFgq83RoeD8he",
"some" : "data",
"other" : "things",
"and" : "so on",
"type" : "element",
"parent" : "cdPhkTpMXi8z6TqMT"
},
{
"id" : "vyjgkuNXRN9KkCd5o",
"some" : "data",
"other" : "things",
"and" : "so on",
"type" : "element",
"parent" : "cdPhkTpMXi8z6TqMT"
},
{
"id" : "f5L5zsSNRSQKWoAXL",
"some" : "data",
"other" : "things",
"and" : "so on",
"type" : "element",
"parent" : "TuibXPe5qMvqdMW6q"
}
So my attempt would be something like this:
Collection.find({}).forEach(function(doc) { // get all documents
var docID = doc._id;
doc.group.forEach(function(group) { // get all groups
var parent = group.id;
group.type = "group";
group.parent = docID;
group.data.forEach(function(element) { // get all elements
element.type ="element";
element.parent = parent;
});
});
});
1) I don't know how to do that in a better way
2) And I don't know how to save the result back to the collection
Fot the groups:
db.myCol.aggregate([{$unwind:"$group"},
{$project:{_id:"$group.id", some:"$group.some",
parent:"$_id", type:{$literal:"group"}}}])
For the Elements:
db.myCol.aggregate([{$unwind:"$group"},
{$unwind:"$group.data"},
{$project:{_id:"$group.data.id", some:"$group.data.some",
parent:"$group.id", type:{$literal:"element"}}}])
And to your second question: You can add an $out step to the aggregation pipeline at the end. For example: {$out:"outputCol"}
I have a JSON generated by Papa Parse from a CSV file that look like this:
{ object, object, object, .... , object }
I need to modify it so it looks like this:
{ "publication" :
{
"id" : 1,
"name" : "name1"
},
"publication" :
{
"id" : 2,
"name" : "name2"
},
"publication" :
{
"id" : 3,
"name" : "name3"
}
}
Where the "id" and "name" are properties within each object.
In other words, I need a JSON that say "publication" and each "publication" occurrence have nested under it the properties names and values of one of the objects above.
How could I achieve this with Javascript?
Thanks
you cannot put many keys with same name...
a solution it's put in array
{
"publication" : [
{
"id" : 1,
"name" : "name1"
},
{
"id" : 2,
"name" : "name2"
},
{
"id" : 3,
"name" : "name3"
}]
}
Is this not an array of publications?
{ publications: [{"id":1, "name":"name1"},
{"id":2, "name":"name2"}.....]}
If I understand it right, you probably mean that you have objects like this:
{"publication" : { "id" : 1, "name" : "name1" }
{"publication" : { "id" : 2, "name" : "name2" }
{"publication" : { "id" : 3, "name" : "name3" }
What you can do in order to have:
{ "publication" : [
{
"id" : 1,
"name" : "name1"
},
{
"id" : 1,
"name" : "name2"
},
{
"id" : 3,
"name" : "name3"
} ]
}
is:
var json = [{"publication" : { "id" : 1, "name" : "name1" }},
{"publication" : { "id" : 2, "name" : "name2" }},
{"publication" : { "id" : 3, "name" : "name3" }}];
var newJson = {"publication" : []};
var i = 0;
for (var item in json) {
var key = json[item];
var obj = {"id" : key["publication"]["id"], "name" : key["publication"]["name"]};
newJson["publication"][i] = obj;
i++;
}
You can check this if you want to print "pretty":
How can I pretty-print JSON using JavaScript?