MongoDB distinct returns empty - mongodb

I can't get collection.distinct to work for me on db.version '4.4.3'. I'm following the example at https://docs.mongodb.com/manual/reference/command/distinct/
{ "_id": 1, "dept": "A", "item": { "sku": "111", "color": "red" }, "sizes": [ "S", "M" ] }
{ "_id": 2, "dept": "A", "item": { "sku": "111", "color": "blue" }, "sizes": [ "M", "L" ] }
{ "_id": 3, "dept": "B", "item": { "sku": "222", "color": "blue" }, "sizes": "S" }
{ "_id": 4, "dept": "A", "item": { "sku": "333", "color": "black" }, "sizes": [ "S" ] }
Then run
db.runCommand ( { distinct: "inventory", key: "dept" } )
I get
{ values: [], ok: 1 }
This doesn't work either:
db.inventory.distinct( "dept" )
[]
I can't get it to work on a local server or a remote server. What gives?

Related

Mongodb Aggregation: how to model a collection to return a tree structure?

https://www.mongodb.com/docs/manual/tutorial/model-tree-structures-with-parent-references/ describes 5 ways to model tree-like structures in MongoDB, and recommends to use $graphlookup to traverse the tree.
All examples of $graphlookup return a flat array of the referenced documents tho, and it's not quite clear how should I use it to return the tree structure of subdocuments within subdocuments within subdocuments etc.
I am flexible with data structure as long as I can get each document by _id regardless of how far from the root it is, and retrieve the whole tree of dereferenced/embedded documents:
[
{
"_id": "a",
"label": "Cat",
"children": [
{
"_id": "b",
"label": "Big cat",
"children": [
{
"_id": "c",
"label": "Lion"
},
{
"_id": "d",
"label": "Jaguar"
},
{
"_id": "e",
"label": "Tiger"
}
]
},
{
"_id": "f",
"label": "Small cat",
"children": [
{
"_id": "g",
"label": "Bay cat"
},
{
"_id": "h",
"label": "Desert lynx"
},
{
"_id": "i",
"label": "Leopardus",
"children": [
{
"_id": "j",
"label": "Guina"
},
{
"_id": "k",
"label": "Tigrillo"
},
{
"_id": "l",
"label": "Ocelot"
}
]
},
{
"_id": "m",
"label": "Lynx"
},
{
"_id": "n",
"label": "Felis",
"children": [
{
"_id": "o",
"label": "Jungle cat"
},
{
"_id": "p",
"label": "Sand cat"
},
{
"_id": "q",
"label": "Wildcat",
"children": [
{
"_id": "r",
"label": "African wildcat"
},
{
"_id": "s",
"label": "European wildcat"
},
{
"_id": "t",
"label": "Domestic cat"
}
]
}
]
}
]
}
]
}
]
How should I store all these animals, and what pipeline operators can recursively populate the nested structure?
I have created the flat list of these cats in https://mongoplayground.net/p/7D8SgIh-85W to play with.
It's possible to create a flat collection and still be able to reconstruct the tree by modeling each document as a graph node with a connection list. Something like:
db={
"catTree": [
{
"_id": "a",
"label": "Cat",
"children": ["b", "f"],
"parent": null
},
{
"_id": "b",
"label": "Panthera",
"children": ["c", "d", "e"],
"parent": "a"
},
{
"_id": "c",
"label": "Lion",
"children": [],
"parent": "b"
},
{
"_id": "d",
"label": "Jaguar",
"children": [],
"parent": "b"
},
{
"_id": "e",
"label": "Tiger",
"children": [],
"parent": "b"
},
{
"_id": "f",
"label": "Small cats",
"children": ["g", "h", "i", "m", "n"],
"parent": "a"
},
{
"_id": "g",
"label": "Bay cat",
"children": [],
"parent": "f"
},
{
"_id": "h",
"label": "Desert lynx",
"children": [],
"parent": "f"
},
{
"_id": "i",
"label": "Leopardus",
"children": ["j", "k", "l"],
"parent": "f"
},
{
"_id": "j",
"label": "Guina",
"children": [],
"parent": "i"
},
{
"_id": "k",
"label": "Tigrillo",
"children": [],
"parent": "i"
},
{
"_id": "l",
"label": "Ocelot",
"children": [],
"parent": "i"
},
{
"_id": "m",
"label": "Lynx",
"children": [],
"parent": "f"
},
{
"_id": "n",
"label": "Felis",
"children": ["o", "p", "q"],
"parent": "f"
},
{
"_id": "o",
"label": "Jungle cat",
"children": [],
"parent": "n"
},
{
"_id": "p",
"label": "Sand cat",
"children": [],
"parent": "n"
},
{
"_id": "q",
"label": "Wildcat",
"children": ["r", "s", "t"],
"parent": "n"
},
{
"_id": "r",
"label": "African wildcat",
"children": [],
"parent": "q"
},
{
"_id": "s",
"label": "European wildcat",
"children": [],
"parent": "q"
},
{
"_id": "t",
"label": "Domestic cat",
"children": [],
"parent": "q"
}
]
}
Using "$graphLookup", a "root" document can be specified and all "children" will be returned, to any depth. Adapting list_to_tree from another javascript answer, the tree can be reconstructed.
db.catTree.aggregate([
{
"$match": {
"_id": "a"
}
},
{
"$graphLookup": {
"from": "catTree",
"startWith": "$children",
"connectFromField": "children",
"connectToField": "_id",
"as": "theKids",
"depthField": "level"
}
},
{
"$set": {
"children": {
"$function": {
"body": "function(root, list) {let map = {}, node, roots = [], i;for (i = 0; i < list.length; i += 1) {map[list[i]._id] = i;list[i].children = [];node = list[i];if (node.parent !== root) {list[map[node.parent]].children.push(node);} else {roots.push(node);}}return roots}",
"args": [
"$_id",
{
"$sortArray": {
"input": "$theKids",
"sortBy": {"level": 1}
}
}
],
"lang": "js"
}
}
}
},
{"$unset": "theKids"}
])
Example output:
[
{
"_id": "a",
"children": [
{
"_id": "b",
"children": [
{
"_id": "c",
"children": [],
"label": "Lion",
"level": NumberLong(1),
"parent": "b"
},
{
"_id": "d",
"children": [],
"label": "Jaguar",
"level": NumberLong(1),
"parent": "b"
},
{
"_id": "e",
"children": [],
"label": "Tiger",
"level": NumberLong(1),
"parent": "b"
}
],
"label": "Panthera",
"level": NumberLong(0),
"parent": "a"
},
{
"_id": "f",
"children": [
{
"_id": "h",
"children": [],
"label": "Desert lynx",
"level": NumberLong(1),
"parent": "f"
},
{
"_id": "g",
"children": [],
"label": "Bay cat",
"level": NumberLong(1),
"parent": "f"
},
{
"_id": "m",
"children": [],
"label": "Lynx",
"level": NumberLong(1),
"parent": "f"
},
{
"_id": "n",
"children": [
{
"_id": "q",
"children": [
{
"_id": "t",
"children": [],
"label": "Domestic cat",
"level": NumberLong(3),
"parent": "q"
},
{
"_id": "r",
"children": [],
"label": "African wildcat",
"level": NumberLong(3),
"parent": "q"
},
{
"_id": "s",
"children": [],
"label": "European wildcat",
"level": NumberLong(3),
"parent": "q"
}
],
"label": "Wildcat",
"level": NumberLong(2),
"parent": "n"
},
{
"_id": "p",
"children": [],
"label": "Sand cat",
"level": NumberLong(2),
"parent": "n"
},
{
"_id": "o",
"children": [],
"label": "Jungle cat",
"level": NumberLong(2),
"parent": "n"
}
],
"label": "Felis",
"level": NumberLong(1),
"parent": "f"
},
{
"_id": "i",
"children": [
{
"_id": "k",
"children": [],
"label": "Tigrillo",
"level": NumberLong(2),
"parent": "i"
},
{
"_id": "j",
"children": [],
"label": "Guina",
"level": NumberLong(2),
"parent": "i"
},
{
"_id": "l",
"children": [],
"label": "Ocelot",
"level": NumberLong(2),
"parent": "i"
}
],
"label": "Leopardus",
"level": NumberLong(1),
"parent": "f"
}
],
"label": "Small cats",
"level": NumberLong(0),
"parent": "a"
}
],
"label": "Cat",
"parent": null
}
]
Try it on mongoplayground.net.

Filter Nested Array Items CosmosDb

Is it possible to filter array items in CosmosDb? for example I just need customer info and the first pet(in an array)
Current result:
[
{
"CustomerId": "100",
"name": "John",
"lastName": "Doe",
"pets": [
{
"id": "pet01",
"CustomerId": "100",
"name": "1st pet"
},
{
"id": "pet02",
"CustomerId": "100",
"name": "2nd pet"
}
]
}
]
Expected:
[
{
"CustomerId": "100",
"name": "John",
"lastName": "Doe",
"pets": [
{
"id": "pet01",
"CustomerId": "100",
"name": "1st pet"
}
]
}
]
You can use ARRAY_SLICE function.
SQL:
SELECT c.CustomerId,c.name,c.lastName,ARRAY_SLICE(c.pets,0,1) as pets
FROM c
Result:
[
{
"CustomerId": "100",
"name": "John",
"lastName": "Doe",
"pets": [
{
"id": "pet01",
"CustomerId": "100",
"name": "1st pet"
}
]
}
]

Clean docs in collection by comparing them with reference

I have a lot of complex JSON objects which are placed in the collection. For example:
{
"name": "Mike",
"price": "444",
"distance": 881,
"someFiend": 123,
"lots": [
{
"aa": "111",
"bb": "222"
},
{
"xx": "000"
}
],
"apps": [
{
"app": 1
},
{
"app": 2
}
]
}
I only want to project only those fields which are present in the following reference document:
{
"name": "",
"price": "",
"lots": [
{
"aa": "",
"bb": ""
}
]
}
Expected output:
{
"name": "Mike",
"price": "444",
"lots": [
{
"aa": "111",
"bb": "222"
}
]
}
Is there any way to iterate all documents in the collection and then filter out fields that are not present in the reference doc?

mongoDB read performance difference between one to many models and normalized models

here are 2 possibilities for a note taking database that will have multiple notes for multiple users to keep track of
1.
[
{
"_id": "abcd",
"userInfo": {
"userID": "1",
"notes": [
{
"noteID": "1",
"text": "123"
},
{
"noteID": "2",
"text": "456"
},
{
"noteID": "3",
"text": "789"
}
]
}
},
{
"_id": "efgh",
"userInfo": {
"userID": "2",
"notes": [
{
"noteID": "1",
"text": "123"
},
{
"noteID": "2",
"text": "456"
}
]
}
}
]
And the 2nd option:
[
{
"_id": "abcd",
"userID": "1",
"noteID": "1",
"text": "123"
},
{
"_id": "efgh",
"userID": "1",
"noteID": "2",
"text": "456"
},
{
"_id": "ijkl",
"userID": "1",
"noteID": "3",
"text": "789"
},
{
"_id": "mnop",
"userID": "2",
"noteID": "1",
"text": "123"
},
{
"_id": "wxyz",
"userID": "2",
"noteID": "2",
"text": "123"
}
]
I'd expect 1 to have a much better performance when it comes to loading notes for a single user(if the user has a ton of notes). However, 2nd option is much better when modifying and adding individual notes.

Why is Robomongo returning an object from db.collection.distinct() instead of an array?

Using the example from the MongoDB reference, I'd expect db.inventory.distinct("dept"); to return an array ["A", "B"], and that's exactly what happens when I run this from the shell. Using Robomongo (on OS X) I instead get an object with name-value pairs, like so: { "0" :"A", "1": "B" }.
This is the setup:
db.inventory.drop();
db.inventory.insert([
{ "_id": 1, "dept": "A", "item": { "sku": "111", "color": "red" },
{ "_id": 2, "dept": "A", "item": { "sku": "111", "color": "blue" },
{ "_id": 3, "dept": "B", "item": { "sku": "222", "color": "blue" },
{ "_id": 4, "dept": "A", "item": { "sku": "333", "color": "black" }
]);
Why is Robomongo behaving different? Can I do anything about it?